#!/usr/local/bin/perl -T

###############################################################################
#							FRAMECAL.PL
#
# Version: 2.1.1
#
# Last Modified:  11 DEC 1998
#
# This program was written by Michael E. Schechter (mschechter@earthlink.net)
# in the course of heavily modifying Selena Sol's Groupware Calendar v3.0.
# Selena Sol can be reached at selena@extropia.com.
#
# You may copy this under the terms of the GNU General Public
# License or the Artistic License which is distributed with
# copies of Perl v5.x for UNIX.
#
# Please send working URLs to mschechter@earthlink.net.  This program is free,
# and will remain free.  Donations to defray the cost of the platform for
# distribution are greatly appreciated.  However, if you are student (of Perl
# or otherwise), or a non-profit organization, and feel you would like to
# make a donation, send it to your favorite charity instead.  If you would
# like to send me money, just drop me an email.
#
# Please see the revision history HTML document to learn all of the changes
# in the current version.  It can be found in the htdocs subdirectory of the
# distribution.  Please read the installation file also found therein.
###############################################################################

# First, tell Perl to bypass the buffer.

$| = 1;

# REQUIRE LIBRARIES #

# Now, let's require the necessary library and setup files using the
# CgiRequire subroutine found in this file.  The subroutine will provide
# us with an error message if any of the files can not be required properly.

# $lib is the path to the directory containing the library files that
# are used by this, and many other, scripts.  Note that the line below
# sets it using a relative path.  On some server setups, you will have to
# change this to an absolute path.

$lib = "../libs";
&CgiRequire("$lib/cgi-lib.pl");

# GET FORM DATA #

# Now we use the cgi-lib.pl subroutine ReadParse to get our form data
# into the hash %form_data.  Note that we rename it from its standard
# value of %in for clarification purposes.  After this, we will be able
# to get all incoming form data by referencing $form_data{'variablename'}.

&ReadParse(*form_data);

# DETERMINE CALENDAR #

# Since this script allows us to keep many different calendars using one
# script, we need to get the calendar to use from the form data.  This
# information will be stored in the key 'calendar'.  We read this information
# in and untaint it.  Note that only alphanumber and an optional / are allowed.
# In order to access this, the original link must have had ?calendar=some/dir
# in the URL.  If this value is omitted, we assume we are using calendar files
# stored in the script directory.

# After getting the calendar, we finish by requiring the calendar specific
# files.

if ($form_data{'calendar'} ne "") {
	$form_data{'calendar'} =~ /^(\w+\/?\w*)/o;
	$calendar_type = "../$1";
} else {
	$calendar_type = ".";
}
&CgiRequire("$calendar_type/calendar.setup", "$calendar_type/auth.setup");
&CgiRequire("$auth_lib/auth-lib.pl");

# IN MAINTENANCE #

# We have the option in the setup file to "shut down" the calendar by
# turning on the $in_maintenance flag.  This allows us to modify a small
# file and upload it, in effect stopping all processing while maintenance
# is performed.  If the value is true, we print out a message to the user
# and stop all further processing.

if ($in_maintenance) {
	&header ("Calendar Unavailable");
	print qq!
</form><center><h3>Calendar Unavailable</h3></center>
<blockquote>I'm sorry, but the calendar is currently unavailable due to
system maintenance.  Please try back in 15 minutes.</blockquote>!;
	&footer;
	exit;
}

# SESSION FILE #

# The session file is used on every pass through the script, to determine
# who is using it on the given pass.  So, we define a variable and set it
# to the value of session_file passed through the form data.  On the first
# pass, this will be blank, and will start us into the authorization process
# in a little while.

if ($form_data{'session_file'} ne "") {
	$form_data{'session_file'} =~ /^(\w+)/o;
	$session_file = $1;
}

# DATE INFORMATION #

# Okay, this is a calendar script, so there should be a lot of date
# variables, right?  This is where we start defining them all.  We
# get the current day, month, and year from the system time.  Note that
# the system returns the month as a number from 0-11, and year returns
# the number of years since 1900, so we need to modify them a little.

# We then set the currentyear for the script by either reading in the
# year passed to us by the form data, or, in the absence of that, we
# set it to the localtime year.  We do the same with the currentmonth.
# We also go ahead and get the name of the currentmonth at this time.

($ltday, $ltmon, $ltyear) = (localtime(time))[3,4,5];
$ltmon += 1;
$ltyear += 1900;
if ($form_data{'year'} ne "") {
	$form_data{'year'} =~ /^(\d{4})/o;
	$currentyear = "$1";
} else {
	$currentyear = "$ltyear";
}
if ($form_data{'month'} ne "") {
	$form_data{'month'} =~ /^(\d{1,2})/o;
	$currentmonth = "$1";
} else {
	$currentmonth = "$ltmon";
}
$current_month_name = $month_hash{$currentmonth};

# DEFINE DATABASE FILES #

# This implementation of the script uses a database file for
# each month and year.  Thus, for January 1999, we will be working
# with a base file called 199901.  We set up the base file
# from the month and year variables we just defined, set the 
# database file to this plus ".events", and then define a lock
# file and temp file value for the base file.  Since we're here,
# we also check to see if the database file currently exists.

$base_file = "$currentyear".sprintf("%.2d", $currentmonth);
$database_file = "$calendar_type/$base_file".".events";
$temp_file = "$temp_lock_dir/$base_file"."_temp.file";
$lock_file = "$temp_lock_dir/$base_file"."_lock.file";
$db_exist = (-e $database_file);

# USER AUTHENTICATION #

# Okay, at this point, we want to find out if the user should actually be
# here.  We use the GetSessionInfo subroutine found in auth-lib.pl, which
# we have already required, to get the user to login, and authenticate them.
# We also chomp the session email, which removes a new line character if one
# exists on it.

($session_file, $session_username, $session_group, $session_name,
 $session_email) =
 &GetSessionInfo($session_file, "$this_script_url?calendar=$calendar_name", *form_data);
chomp $session_email;

# WHAT DO YOU WANT ME TO DO? #

# Each button on the forms that are presented, and most links, provide a tag
# called 'action'.  This form data variable tells the script what button
# or type of link you selected, and thus, what you want to do.  So, we grab
# this data, and do it with a 'perl-esque' Case statement.  Note that if
# no action is defined, we must want to see the month table, and we also have
# the option to clean up old datafiles if the URL we call the script with
# has the 'first_pass=on' value in it.  Note that no portion of the script
# will ever include that item, so if you want automatic clean up of files,
# you will have to set it in your URL that you call the script with, and
# set a number of months to save in your calendar.setup file.  This is the
# end of the MAIN section of the script.  From here on out, we are just
# calling subroutines.

$action = $form_data{'action'};
CASE: {
	if ($action =~ /^view_month/i)   { do { view_month_sub();       last CASE; } }
	if ($action =~ /^view_day/i)     { do { view_day_sub();         last CASE; } }
	if ($action =~ /^view_search/i)  { do { view_search_sub();		last CASE; } }
	if ($action =~ /^Add Item/i)     { do { add_item_form_sub();    last CASE; } }
	if ($action =~ /^Add Event/i)    { do { add_event_sub();        last CASE; } }
	if ($action =~ /^Modify Item/i)  { do { modify_item_form_sub(); last CASE; } }
	if ($action =~ /^Modify Event/i) { do { modify_event_sub();     last CASE; } }
	if ($action =~ /^Delete Item/i)  { do { delete_item_form_sub(); last CASE; } }
	if ($action =~ /^Delete Event/i) { do { delete_event_sub();     last CASE; } }
	if ($action =~ /^Search/i)		 { do { search_form();			last CASE; } }
	if ($action =~ /^Find Events/i)  { do { search_events();		last CASE; } }
	if ($form_data{'first_pass'} eq "on") { &trim_events(); }
	&view_cal_sub();
}

# SUB VIEW_CAL_SUB #

# Okay, if we have called this subroutine, that means we want to print out the
# table formatted month.

sub view_cal_sub {

# We need to make an array that is formatted for the current month, i.e., has
# the day numbers in the correct indices in the array, so we call the
# make_month_array subroutine with the julian day for the first day of the month
# and year that we are in.

	my (@mymonth) = &make_month_array(&jday($currentmonth,1,$currentyear));
	my ($size_of_mymonth);
	my ($variable_list,$next_month,$next_year,$prev_month,$prev_year);
	my ($next_link,$prev_link,$month_link,$day,%event_days);
	my ($count_till_last_day,$weekday,$day_number,$td_color);
	$size_of_mymonth = scalar(@mymonth);

# We start to print out our HTML page here, with the header sub being called.

	&header ("Calendar: $current_month_name - $currentyear");

# We now create our Next Month, Prev. Month, and View Month links.  We do this
# by just increasing the month by one for Next, decreasing it by one for Prev.,
# and checking to see if we thus move into another year, and correct for that.
# We then concatenate together three strings to be used to hold the link information
# for these values, providing all the information that would be required by the script.

	$variable_list = "";
	$variable_list .= "calendar=$form_data{'calendar'}";
	$variable_list .= "&session_file=$session_file";
	$next_month = $currentmonth + 1;
	$next_year = $currentyear;
	$prev_month = $currentmonth - 1;
	$prev_year = $currentyear;
	if ($next_month > 12) {
		$next_month = 1;
		$next_year++;
	}
	if ($prev_month < 1) {
		$prev_month = 12;
		$prev_year--;
	}
	$next_link = $variable_list."&month=$next_month&year=$next_year";
	$prev_link = $variable_list."&month=$prev_month&year=$prev_year";
	$month_link = "calendar=$form_data{'calendar'}&session_file=$session_file";
	$month_link .= "&action=view_month&month=$currentmonth&year=$currentyear";

# Now that we have the links together, we put them in a small one row table at the
# top of the month table, and then start the month table, setting its title.

	print qq!
<center>
<table><tr><td align="left" valign="bottom" width="80"><font size="1">
<a href="$this_script_url?$prev_link">Prev. Month</a></font></td>
<td align="center" valign="bottom" width="80"><font size="1">
<a href="$this_script_url?$month_link" target="$day_frame">View Month</a></font></td>
<td align="right" valign="bottom" width="80"><font size="1">
<a href="$this_script_url?$next_link">Next Month</a></font></td></tr></table>
<table border="2" cellpadding="2" cellspacing="1">
<tr><td colspan="7" align="center" bgcolor=$apptcol>
<b><font color=$hitxt>$current_month_name - $currentyear</font></b></td></tr><tr>!;

# Print out the days of the week in table format.  For every day (foreach $day) in
# our list of days (@day_names) we create a cell, and then end the row.

	foreach $day (@day_names) {
		print "<td align=\"center\" width=\"$day_cell_width\"><b><font size=\"-1\">",
			  "$day</font></b></td>\n";
	}
	print "</tr>\n<tr>\n";

# If our database file that we defined above exists, we need to open it and index
# the days that have events associated with them.  So, if it exists, we open
# up the file and read through it.  For each entry, we extract the day, then see
# if that day number exists in the hash %event_days.  If it does, we add to the
# value associated with the $day key, if not, its the first one, so we set the value
# to 1 for that key.  Thus, this provides us with a list of days that have events
# for the month, and how many events that day has.

	if ($db_exist) {
		open (DATABASE, "$database_file") || &open_error($database_file);
		while (<DATABASE>) {
			$day = (split (/\|/, $_))[0];
			if ($event_days{$day}) {
				$event_days{$day}++;
			} else {
				$event_days{$day} = 1;
			}
		}
		close (DATABASE);
	}

# We initialize the variable $count_till_last_day, which we will use to be sure
# we don't add too many <tr>s at the end of the calendar.  We also initialize
# $weekday, which we will use to be sure that we end one row and start another
# every seven days, to maintain a two-diminsional table.

	$count_till_last_day = 0;
	$weekday = 0;

# We now need to create a cell in the table for each day in the month, using
# the mymonth array we created when we first entered our subroutine.

	foreach $day_number (@mymonth) {

# We increment our two variables for each pass through the loop.  When we get
# to 7 in weekday, we have reached the end of a week, so we reset it.

		$count_till_last_day++;
		$weekday++;
		$weekday = 0 if ($weekday > 6);

# For each day, we need to find out what type it is, so we can set the
# background color for the cell.  There are three options: the current
# day of the year, a day with an event, and a day that is neither.  This
# conditional statement sets the cell color variable that will be used to
# format the day cell.

		unless ($day_number == $ltday && $currentyear == $ltyear
				&& $currentmonth == $ltmon) {
			if ($event_days{$day_number}) {
				$td_color = " bgcolor=$evntcol";
			} else {
				$td_color = "";
			}
		} else {
			$td_color = " bgcolor=$tdycol";
		}

# We now print out the cell information for the day.  If the day contains an
# event as defined in the index that we made, we create the link to allow us
# to view that day's events.  Otherwise, we will just print out the day number.
# Note that if a day has events, we will also include the number of events on
# that day, which is also determined from our index of events for the month.

		print qq!<td valign="top"$td_color>!;
		if ($event_days{$day_number}) {
			$variable_list = "";
			$variable_list = "day=$day_number&year=$currentyear";
			$variable_list .= "&month=$currentmonth";
			$variable_list .= "&session_file=$session_file";
			$variable_list .= "&calendar=$form_data{'calendar'}";
			$variable_list .= "&action=view_day";
			print qq!
<center><font size="1">
<a href="$this_script_url?$variable_list" target="$day_frame">$day_number</a><br>
( $event_days{$day_number} )!;
		} else {
			print qq!<center><font size="1">$day_number<br>&nbsp;!;
		}
		print "</font></center></td>\n";

# If we have have reached the end of the week, we print out the row ending tag.
# We also start the next row, unless we are at the end of the month.

		if ($weekday == 0) {
			print "</tr>\n";
			unless ($count_till_last_day == $size_of_mymonth) {
				print "<tr>";
			}
		}
	}

# Print the end of the table, and use two subroutines to provide the user
# with selection items to jump to another month and year directly.
# We also generate the end of our form, with all the tags containing the
# information we will need to pass on for the next pass.  These items are
# for all users.  Note that we have to start a new form so we can target
# frames for output.

	print qq!</table><p>!;
	&select_a_month;
	&select_a_year;
	print qq!
<p><input type="submit" name="action" value="Change Month/Year"></center></form>
<center><form method="post" action="$this_script_url" target="$day_frame">
<input type="hidden" name="session_file" value="$session_file">
<input type="hidden" name="month" value="$currentmonth">
<input type="hidden" name="year" value="$currentyear">
<input type="hidden" name="calendar" value="$form_data{'calendar'}">
<input type="submit" name="action" value="Search">!;

# If the session group is user or admin, we have found someone who is allowed
# to post events to the calendar, so we provide an Add Item button.

	if ($session_group eq "user" || $session_group eq "admin") {
		print qq!
<input type="submit" name="action" value="Add Item">!;

# If the session group is admin, we provide another form to access the
# adminstration script to provide an online way to administer users,
# and pending users if the $auth_alt_user_file is being used as well.

		if ($session_group eq "admin") {
			print qq!
</form><form method="post" action="$admin_script" target="$day_frame">
<input type="hidden" name="session_file" value="$session_file">
<input type="hidden" name="calendar" value="$form_data{'calendar'}">
<input type="submit" name="action" value="User Admin">!;
			if ($auth_alt_user_file) {
				print qq!
<input type="submit" name="action" value="Register Users">!;
			}
		}

# If we are using online help, we now provide the links to the
# help script with the correct help topic number.

		if ($use_help) {
			print "<p>";
			if ($session_group eq "user") {
				&help_link ("2");
			} else {
				&help_link ("3");
			}
		}
	} else {
		if ($use_help) {
			print "<p>";
			&help_link ("1");
		}
	}

# Finally, we give the user some information that lets them know that we know
# who they are, and what access level they are at.  We then close the page with
# the standard footer.

	print qq!
</form><p><font size="-1">$session_name<br>Access Level: $session_group</font></center>!;
	&footer;
}

# SUB VIEW_DAY_SUB #

# If we have called this subroutine, it means we want to see the events for
# a certain day, normally linked from the Month Table.

sub view_day_sub {
	my ($day,$username,$time,$id,$item_found);

# We start off by printing up the header information for display, along with
# the date of the event.  We then check to see if the database file exists for
# this days month and year.  Normally, we would only access this from a link
# that tells us that the file exists, but there are some tricks that can be
# used in the HTML document that calls the script that require this check.

	&header ("$current_month_name $form_data{'day'}, $currentyear");
	print qq!
<font size="+1"><b>$current_month_name $form_data{'day'}, $currentyear
</b></font><hr width="75%" align="left">!;
	if ($db_exist) {

# If the file exists, we want to start printing out the information for the
# day.  We start by printing out a <ul> to indent all the events.  Then we
# open up the database file.

		print "<ul>";
		open (DAYFILE, "$database_file") || &open_error($database_file);
		while (<DAYFILE>) {

# We read through the file one line at a time, splitting the items in each line,
# so we have the day and id numbers of each item therein.  We then check to see
# if the day of the event is the same as the day we are trying to access from the
# form.  If it is, we print out the event information using the print_event subroutine.
# We then print out the <hr> to delineate our events.

			($day,$time,$username,$id) = split (/\|/, $_);
			chomp ($id);
			if ($day eq $form_data{'day'}) {
				&print_event("$id");
				print "<hr align=\"left\">";
				$item_found = "yes";
			}
		}
		close (DAYFILE);
		print "</ul>";

# If the session group is not public, or we have not found events, print out
# form buttons to allow us to modify or delete events for the displayed day.

		unless ($session_group eq "public" || $item_found ne "yes") {
			print qq!
<center>
<input type="hidden" name="day" value="$form_data{'day'}">
<input type="hidden" name="month" value="$currentmonth">
<input type="hidden" name="year" value="$currentyear">
<input type="submit" name="action" value="Modify Item">
<input type="submit" name="action" value="Delete Item"></center>!;
		}
		print "</form>";
	}
	
# If we didn't find any events for the day, print out a message stating that
# to the user.

	if ($item_found ne "yes") {
		print qq!
<center><h3>No Events For Day</h3></center><blockquote>
I'm sorry, but there are not any events scheduled for
the current day. Please check back again later for future
additions.</blockquote>!;
	}

# If we are using help in this script, print out the help topic link.
# Then, close the HTML with the standard footer.

	if ($use_help) {
		print "<center>";
		&help_link ("9");
		print "</center><p>";
	}
	&footer;
}

# SUB VIEW_MONTH_SUB #

# If we have called this subroutine, it means we want to see all of the
# events for the selected month.

sub view_month_sub {
	my ($day,$username,$time,$id,$item_found);
	my ($last_day) = "";

# We start by printing out the header for the page, and we go ahead and
# close the form tag immediately, since we don't have any interaction on
# the page that is generated.  We then check to see if the database file
# for the selected month exists, and if it does, we open it.

	&header ("$current_month_name, $currentyear");
	print "</form>";
	if ($db_exist) {
		open (MONTHFILE, "$database_file") || &open_error($database_file);
		while (<MONTHFILE>) {

# We now read through the database file one line at a time, extracting
# the id number from each, and removing the new line character.

			($day, $time, $username, $id) = split (/\|/,$_);
			chomp $id;

# We need to keep track of what the last day was, so we can break up the list
# by days.  So, we look at the day from the current line.  If it is not equal
# to the last day we looked at, we print out the new days title, and set the
# current line's day to the last day for the next pass.  Else, we have another
# event on the same day, so we just supply an <hr> to separate the events.

			if ($last_day ne $day) {
				print ("</ul>") unless ($last_day eq "");
				$last_day = $day;
				print qq!
<font size="+1"><b>$current_month_name $day, $currentyear
</b></font><hr width="75%" align="left"><ul>!;
			} else {
				print ("<hr align=\"left\">");
			}

# We now go through the process of printing out the event's information as
# we did in the view day subroutine.

			&print_event("$id");
			$item_found = "yes";
		}
		close (MONTHFILE);
	}

# If we found events, we need to end our indentation and provide a final
# <hr> to separate out the rest of the information we will provide.

	print ("<hr align=\"left\"></ul>") unless ($item_found ne "yes");

# If we didn't find events, we need to tell the user that there are no
# events scheduled for the month.

	if ($item_found ne "yes") {
		print qq!
<center><h3>No Events For Month</h3></center><blockquote>
I'm sorry, but there are not any events scheduled for
the current month. Please check back again later for future
additions.</blockquote>!;
	}

# If we are using help with the calendar, we print out the link to
# the help topic, and then we close the HTML page with the standard
# footer.

	if ($use_help) {
		print "<p><center>";
		&help_link ("8");
		print "</center><p>";
	}
	&footer;
}

# SUB VIEW_SEARCH_SUB #

# If this subroutine has been selected, it means that someone is trying to
# get the details on an event that was returned as a hit from a previous search.

sub view_search_sub {
	my ($day,$id);

# The extra info passed by this type of link is the actual id number of the event
# that we want to look at, as we will only be looking at one at a time.  We need
# to untaint this value in order to open it.  We also get the day of the event
# from the link.

	$form_data{'id'} =~ /^(\d+)/o;
	$id = $1;
	$day = $form_data{'day'};

# We now print out the standard HTML header, and close out the form since there
# is not interaction options for this subroutine's output, especially since it
# will be opened in its own "mini-window".

	&header ("$current_month_name $day, $currentyear");
	print "</form>";

# Now we just print out the information for the event as we have in the previous
# event displaying subroutines.  Nothing new here.  We of course close with the
# standard footer.

	print qq!
<font size="+1"><b>$current_month_name $day, $currentyear
</b></font><hr width="75%" align="left"><ul>!;
	&print_event("$id");
	print ("<hr align=\"left\"></ul>");
	&footer;
}

# SUB ADD_ITEM_FORM_SUB #

# If this subroutine has been called, it means we want to print out the
# form to allow the user to add an event to the database.

# This subroutine is very simple.  We start the HTML, provide a subject,
# then call the submission_form subroutine to print out the main form.
# We then provide the appropriate form buttons, and finish with the footer.

sub add_item_form_sub {
	&header ("Add an Item to $cal_name Calendar");
	print "<center><h3>Add Event to the Database</h3></center>";
	&submission_form;
	print qq!
<center><p>
<input type="submit" name="action" value="Add Event">
<input type="reset" value="Clear This Form"></center></form>!;
	&footer;
}

# SUB ADD_EVENT_SUB #

# If we are calling this subroutine, it means someone has entered information
# for a new event, and we need to add it into our database.

sub add_event_sub {
	my ($n_days,$var_name,$id,$value,$subject,$time,$time_zone);
	my ($location,$dur_hrs,$day,$body,$new_row);
	my (@notify_users,$missing_info,$dur_mins,$linkurl,$linktitle);
	my ($notified,$new_event,$to_notify,$name,$email);

# We initialize our variable to check for missing form data, then
# print out our standard header.  We also get the number of days
# in the current month and year.

	$missing_info = 0;
	&header ("Adding an Item to the $cal_name Calendar Database");
	$n_days = &last_day($currentmonth,$currentyear);

# We do some error checking now.  First, we see if the user tried to
# add an event on a day that doesn't exist.  If so, we call the
# invalid_date subroutine.  If the date is valid, we look to see if
# all of the fields in @req_fields have been filled in.  We also
# check that if the session name is blank, the user has entered a
# name and email address to go with the event.

	if ($form_data{'day'} > $n_days) {
		&invalid_date ($n_days,$form_data{'day'});
	} else {
		foreach $var_name (@req_fields) {
			if ($form_data{$var_name} eq "") {
				$missing_info = 1;
			}
		}
		if ($session_name eq "" && (($form_data{'real_name'} eq "") ||
			($form_data{'email'} eq ""))) {
			$missing_info = 1;
		}

# If we have missing information, we print out an error message and
# exit the script.

		if ($missing_info) {
			print qq!
</form><h3><center>Error in Add Event Form</center></h3><blockquote>
I'm very sorry but you did not supply all the information
required for the event addition.  Please hit the back
button and try again.</blockquote>!;
			&footer;
			exit;
		}

# If we have made it this far, we know that all the required fields have
# been filled in and the user has supplied us with a valid date.  We therefore
# assign an id number to the event using the counter subroutine, then we
# go through each item in the @field_values array to clean up our user input.
# We first strip out any image tags the user may have entered.  Next we strip
# out any server side include tags the user may have entered.  If we are not
# allowing HTML, we strip out any remaining HTML tags.  We then remove any
# Windows hard returns, change any double occurrences of new line into a
# paragraph tag, any single new lines with a break line tag, and any pipe symbols
# with a colon.

		$id = &counter($counter_file);
		foreach $value (@field_values) {
			$form_data{$value} =~ s/<\/?IMG(.|\n)*?>//gi;
			$form_data{$value} =~ s/<!--(.|\n)*?-->//g;
			if ($strip_html) {
				$form_data{$value} =~ s/<(.|\n)*?>//g;
			}
			$form_data{$value} =~ s/\r//g;
			$form_data{$value} =~ s/\n\n/<P>/g;
			$form_data{$value} =~ s/\n/<BR>/g;
			$form_data{$value} =~ s/\|/:/g;
		}

# If no authentication is being used on the calendar, we assign the
# entered real name and email values from the form to the session_name
# and session_email variables.

		if ($session_name eq "") {
			$session_name = "$form_data{'real_name'}";
			$session_email = "$form_data{'email'}";
		}

# If we are allowing use of the notify users option, we process the multiple
# select list by splitting the email addresses into an array, then join
# the array with commas.

		if ($form_data{'notify'} eq "on") {
			@notify_users = split ("\0", $form_data{'mail_choices'});
			$notified = join (",", @notify_users);
		}

# We assign the rest of our form data information to variables.  Along the
# way we create our new line that will go into the database file.  Note that
# if no duration time was entered, we set the event up to be displayed as a
# general information event, applicable to the whole day.

		$day = "$form_data{'day'}";
		$time_zone = "$form_data{'time_zone'}";
		$dur_hrs = "$form_data{'dur_hrs'}";
		$dur_mins = "$form_data{'dur_mins'}";
		if ($dur_hrs || $dur_mins) {
			$time = "$form_data{'time'}";
		} else {
			$time = '     ';
		}
		$name = "$session_name";
		$email = "$session_email";
		if (($form_data{'linktitle'} ne "") && ($form_data{'linkurl'} ne "")) {
			$linktitle = "$form_data{'linktitle'}";
			$form_data{'linkurl'} =~ s/\\/\//g;
			if ($form_data{'linkurl'} =~ /^http(s?)\:\/\//) {
				$linkurl = "$form_data{'linkurl'}";
			} else {
				$linkurl = "http://$form_data{'linkurl'}";
			}
		} else {
			$linkurl = "";
			$linktitle = "";
		}
		$location = "$form_data{'location'}";
		$subject = "$form_data{'subject'}";
		$body = "$form_data{'body'}";
		$new_row = "$day\|$time\|$session_username\|$id";

# We now fill in the new_event variable with a string that will be used to
# create the event file for this particular event.  If you are going to modify
# information stored for each event, this is another place you will have to make
# modifications.

		$new_event = "time->$time\ntimezone->$time_zone\ndurationhrs->$dur_hrs\n";
		$new_event .= "durationmins->$dur_mins\nname->$name\nemail->$email\n";
		$new_event .= "notified->$notified\nlinkurl->$linkurl\nlinktitle->$linktitle\n";
		$new_event .= "location->$location\nsubject->$subject\nbody->$body\n";

# We are now ready to start writing to files.  First we get our filelock.  If our
# database exists, we open it in append mode.  If it does not, we create it and
# open it at the same time.  We then print our new row to the database, close
# the database, release our file lock, and sort the events in the database file.

		&GetFileLock ("$lock_file");
		if ($db_exist) {
			open (DATABASE, ">>$database_file") || &open_error($database_file);
		} else {
			open (DATABASE, ">$database_file") || &open_error($database_file);
		}
		print DATABASE "$new_row\n";
		close (DATABASE);
		&ReleaseFileLock ("$lock_file");
		&sort_events ();

# We now need to create our new event file.  First we must untaint the id number
# that will be used as the file name.  We then open and create the file, and
# print to it the string that we stored in the new_event variable.  We of course
# then close the file.

		$id =~ /(\d+)/o;
		$id = $1;
		open (EVENTFILE, ">$path_to_events/$id") || &open_error("event file $id");
		print EVENTFILE "$new_event";
		close (EVENTFILE);

# We now print out some information to the user regarding the addition of the
# event to the calendar database, and close it out with the required form data
# tags and the standard footer.

		print qq!
</form><center><h3>Your item has been added. Thanks.</h3>
<form method="post" action="$this_script_url" target="$month_frame">
<input type="hidden" name="month" value="$currentmonth">
<input type="hidden" name="year" value="$currentyear">
<input type="hidden" name="session_file" value="$session_file">
<input type="hidden" name="calendar" value="$form_data{'calendar'}">
<input type="submit" name="action" value="Refresh Calendar"></form></center>!;
		&footer;

# If we are allowing notification of users about events, we put together
# our mailing list from the information passed to us via the form.  We add
# the administrator onto the list if she has been set up to receive notifications,
# and we then call the notification subroutine with the information to
# create the message with.

		if ($allow_notify && ($form_data{'notify'} eq "on") && $notified) {
			$to_notify = "$notified";
		}
		if ($notify_event) {
			$to_notify = "$auth_admin_email_address,$to_notify";
		}
		if ($to_notify) {
			&notification ($day,$time,$time_zone,$dur_hrs,$dur_mins,
						   $to_notify,$location,$subject,$body,"1");
		}
	}
}

# SUB MODIFY_ITEM_FORM_SUB #

# If we have called this subroutine, it means we need to generate the form
# to allow the user to modify an item in the database.

# This subroutine is very simple.  We start our HTML, place some hidden variables
# that will tell the modify subroutine who modified the item, then print out a
# table of events that we are allowed to modify.  We pass a parameter to the
# subroutine to let it know we want the modify table form.  We then call the
# submission form subroutine to get the modify variety of the form, and then
# print out some helpful notes to the user to let them know how to use the
# form.  Then supply buttons, and close the HTML using the standard footer.

sub modify_item_form_sub {
	&header ("Modify an Item");
	print qq!
<input type="hidden" name="username" value="$session_username">
<input type="hidden" name="real_name" value="$session_name">
<input type="hidden" name="email" value="$session_email">!;
	&event_table (1);
	print "</center>";
	&submission_form("modify");
	print "<blockquote><font size=\"1\">";
if ($allow_notify) {
	print qq!
<p>Note: In the &quot;Notify&quot; selection
box above, be aware that those already notified when the event was added
will be notified of the modification. Select only additional people to
notify of the event if you need to.!;
}
	print qq!
<p>Note: Make sure to select an item to modify
using the radio buttons on the top table.  Then change any of
the form inputs you want changed, leaving the others as they
are.  Feel free to cut and paste from the top table to the
bottom table if you only need to change a small amount of
text.</font></blockquote><center>
<input type="hidden" name="orig_year" value="$currentyear">
<input type="hidden" name="orig_month" value="$currentmonth">
<input type="submit" name="action" value="Modify Event">
<input type="reset" value="Clear This Form"></center></form>!;
	&footer;
}

# SUB DELETE_ITEM_FORM_SUB #

# If we have called this subroutine, it means we want to create the form
# to allow the user to delete items from the events database.

# This subroutine is very simple.  We start the HTML, provide a list of events
# for the user using the event_table subroutine, with a parameter to tell the
# subroutine that we want the delete form of the table, then provide buttons
# to the user, and close with the standard footer.

sub delete_item_form_sub {
	&header ("Delete an Item");
	&event_table (0);
	print qq!
<input type="hidden" name="month" value="$currentmonth">
<input type="hidden" name="year" value="$currentyear">
<input type="submit" name="action" value="Delete Event">
<input type="reset" value="Clear This Form"></center></form>!;
	&footer;
}

# SUB DELETE_EVENT_SUB #

# If we have called this subroutine, the user has requested to delete an
# event from the calendar database, using the form generate above.

sub delete_event_sub {
	my (@grepfields,$id);
	my (@del_events,%del_events,$i,$to_notify,$day);
	my ($time,$time_zone,$dur_hrs,$dur_mins,$name,$email,$notified);
	my ($linkurl,$linktitle,$location,$subject,$body);

# We need to create an index of all the events the user has requested to
# delete.  We first split the information from the checkboxes on the form
# into an array, then fill our %del_events hash with this information so
# we don't have to loop through the array later.

	@del_events = split("\0", $form_data{'item_to_mod_del'});
	foreach $i (@del_events) {
		$del_events{"$i"} = 1;
	}

# We check to see if the @del_events array is empty.  If it is, the user
# didn't actually select any events to delete, so we print out an error message.
# If it is not empty, we start processing the deletion.

	unless (@del_events) {
		&header ("Woopsy");
		print qq!
</form><center><h3>Delete an Item in the Database Error</h3></center>
<blockquote>
I'm sorry, I was not able to modify the database because
none of the checkboxes on the table were selected, so I was
not sure which item to delete.  Would you please make sure
that you select an item. Just hit your back button. Thanks.</blockquote>!;
	} else {

# We are now processing the deletion.  First, we get our lock file in place
# to prevent someone else from modifying the file while we are trying to.
# We then open up the temp file and database file specific to the events
# database we will be deleting from.

		&GetFileLock ("$lock_file");
		open (TEMP, ">$temp_file") || &open_error($temp_file);
		open (DATA, "$database_file") || &open_error($database_file);

# We now read through our database file one line at a time.  For each line,
# we get the event id from the line, as well as the day, remove the new line
# character from the id number, and check to see if the id number is in our
# index of events to delete.  If it is not, we print the item to the temp
# file.

		while (<DATA>) {
			@grepfields=split(/\|/,$_);
			$id = pop (@grepfields);
			$day = shift (@grepfields);
			chomp $id;
			unless ($del_events{$id}) {
				print TEMP "$_";
			} else {

# If the id number is in our index of items to delete, we do not print the line
# to the temp file.  Instead, we check to see if we want to notify people of the
# change.  If we do, we get the information about the event from its file, and
# prepare to notify people.
				
				($time,$time_zone,$dur_hrs,$dur_mins,$name,$email,$notified,
			 	 $linkurl,$linktitle,$location,$subject,$body)
			 	 = &get_event_info("$id");

				if ($allow_notify) {
					$to_notify = "$notified";
				}

# If the administrator wants notification of event changes, we add their address
# onto the list of people to notify.

				if ($notify_event) {
					$to_notify = "$auth_admin_email_address,$to_notify";
				}

# If the people to notify is not empty, we send out the message to everyone
# using the notification subroutine, with the final value set to tell that
# subroutine that it is a deletion.

				if ($to_notify) {
					&notification ($day,$time,$time_zone,$dur_hrs,$dur_mins,
								   $to_notify,$location,$subject,$body,"0");
				}

# We now untaint the id number, and use it to delete the event file associated
# with the event.

				$id =~ /(\d*)/o;
				$id = $1;
				unlink ("$path_to_events/$id");
			}
		}

# We are now done reading through the DATA file, so we close it and the TEMP file
# as well.  We remove the DATA file, and replace it with the TEMP file, which
# now contains all the information of the original file, minus the events that
# we wanted to delete, then release the file lock.

		close (DATA);
		close (TEMP);
		unlink ("$database_file");
		rename ($temp_file, $database_file);
		&ReleaseFileLock ("$lock_file");

# We are now done with all of our processing, so we let the user know that
# we are done, and provide a button to refresh the Month Table view in the
# month frame.  We close the HTML with the standard footer.

		&header ("Deleted an Item from the $cal_name Calendar");
		print qq!
</form><center><h3>Your Event(s) have been Deleted.</h3><p>
<form method="post" action="$this_script_url" target="$month_frame">
<input type="hidden" name="month" value="$currentmonth">
<input type="hidden" name="year" value="$currentyear">
<input type="hidden" name="session_file" value="$session_file">
<input type="hidden" name="calendar" value="$form_data{'calendar'}">
<input type="submit" name="action" value="Refresh Calendar">
</form></center>!;
	}
	&footer;
}

# SUB MODIFY_EVENT_SUB #

# If we have called this subroutine, it means a user has requeted to modify
# an event in the database file.

sub modify_event_sub {
	my ($n_days,$id,$new_line,$value,@notify_users,$notified);
	my (@fields,$temp_db,$temp_temp,$temp_lock,$temp_base);
	my ($subject,$time,$time_zone,$orig_year,$orig_month,$mod_item);
	my ($location,$dur_hrs,$day,$body,$name,$email);
	my ($dur_mins,$linkurl,$linktitle,$to_notify,$username);

# Okay, let's go ahead and print out the standard header to get started here.
# We also grab the item to modify from the form data, untaint it, and place
# it into the mod_item variable.

	&header("Modify an Item in the Database");
	$form_data{'item_to_mod_del'} =~ /^(\d+)/o;
	$mod_item= $1;

# We now need to do some error checking.  First we check to see if the user
# has tried to modify an event by placing it into a day that does not exist.
# If they have, we call the invalid date subroutine and exit.

	$n_days = &last_day($currentmonth,$currentyear);
	if ($form_data{'day'} > $n_days) {
		&invalid_date ($n_days,$form_data{'day'});
	}

# If mod_item doesn't have a value in it, that means the user forgot to
# select an event from the table presented.  We print out an error message
# to let them know that.

	if ($mod_item eq "") {
		print qq!
</form><center><h3>Modifying an Item in the Database Error</h3></center>
<blockquote>
I'm sorry, I was not able to modify the database because
none of the radio buttons on the table were selected, so I was
not sure which item to modify.  Would you please make sure
that you select an item \&quot;and\&quot; fill in the new information.
Just hit your back button.  Thanks.</blockquote>!;
	} else {

# If we have made it to here, we are ready to modify our selected event.
# We read in the original year and original month form data variables, because
# we want to be sure that if the user is modifying an event in a way that
# would move it into a different month, we can handle it.

		$form_data{'orig_year'} =~ /^(\d{4})/o;
		$orig_year = $1;
		$form_data{'orig_month'} =~ /^(\d{1,2})/o;
		$orig_month = sprintf("%.2d", $1);
		$temp_base = "$orig_year$orig_month";
		$temp_db = "$calendar_type/$temp_base".".events";
		$temp_temp = "$temp_lock_dir/$temp_base"."_temp.file";
		$temp_lock = "$temp_lock_dir/$temp_base"."_lock.file";

# We are now ready to open up the original database file, so we first lock it,
# open up a temp file, and go through the database, looking for the id number
# we are going to modify.  If the id is not the item we are going to modify,
# we print it to the temp file.  Otherwise, set the fields we have into our
# old fields variables.  We then close the temp file and original database,
# unlink the original database, and rename the temp file to the original database.

		&GetFileLock ("$temp_lock");
		open (TEMPFILE, ">$temp_temp") || &open_error($temp_temp);
		open (DATABASE, "$temp_db") || &open_error($temp_db);
		while (<DATABASE>) {
			@fields = split (/\|/, $_);
			$id = pop(@fields);
			chomp $id;
			push (@fields, $id);
			if ($id ne "$mod_item") {
				print TEMPFILE "$_";
			} else {
				($day,$time,$username,$mod_item) = @fields;
				$mod_item =~ /^(\d+)/o;
				$mod_item = $1;
			}
		}
		close (TEMPFILE);
		close (DATABASE);
		unlink ("$temp_db");
		rename ($temp_temp, $temp_db);
		&ReleaseFileLock("$temp_lock");

# We get the information on our event to modify from the get_event_info subroutine.

		($time,$time_zone,$dur_hrs,$dur_mins,$name,$email,$notified,
	 	 $linkurl,$linktitle,$location,$subject,$body) = &get_event_info("$mod_item");

# We now go through all of our form data values.  If the form data value
# is not blank, we do the same sort of formatting we did when we added an item
# to the database.

		foreach $value (@field_values) {
			if ($form_data{$value} ne "") {
				$form_data{$value} =~ s/<P>/\n\n/gi;
				$form_data{$value} =~ s/<BR>/\n/gi;
				$form_data{$value} =~ s/<\/?IMG(.|\n)*?>//gi;
				$form_data{$value} =~ s/<!--(.|\n)*?-->//g;
				if ($strip_html) {
					$form_data{$value} =~ s/<(.|\n)*?>//g;
				}
				$form_data{$value} =~ s/\r//g;
				$form_data{$value} =~ s/\n\n/<P>/g;
				$form_data{$value} =~ s/\n/<BR>/g;
				$form_data{$value} =~ s/\|/:/g;
			}
		}

# We now go through all of our form data, and update our event if the corresponding
# form date value is present.

		$day = $form_data{'day'} if ($form_data{'day'} ne "");
		$username = $form_data{'username'} if ($form_data{'username'} ne "");
		$time_zone = $form_data{'time_zone'} if ($form_data{'time_zone'} ne "");
		$name = $form_data{'real_name'} if ($form_data{'real_name'} ne "");
		$email = $form_data{'email'} if ($form_data{'email'} ne "");
		$location = $form_data{'location'} if ($form_data{'location'} ne "");
		$subject = $form_data{'subject'} if ($form_data{'subject'} ne "");
		$body = $form_data{'body'} if ($form_data{'body'} ne "");
		$dur_hrs = $form_data{'dur_hrs'} if ($form_data{'dur_hrs'} ne "");
		$dur_mins = $form_data{'dur_mins'} if ($form_data{'dur_mins'} ne "");
		if ($dur_hrs || $dur_mins) {
			$time = $form_data{'time'} if ($form_data{'time'} ne "");
			$time = "09:00" if ($time eq '     ');
		} else {
			$time = '     ';
		}

# With the notification service turned on, however, we need to do some extra
# formatting.  The user can add new people to be notified after the event
# has been added.  We bring in the data from the form, split it, and
# add the email addresses to the notify_users array.  If we did indeed have
# people selected to be notified (@notify_users > 0), we need to merge them
# into our original list of attendees.  We do this by using the %seen hash.
# We split out the original list and put it into @old_users.  We then
# go through each array, and add them to the hash.  With the %seen hash, if there
# is a repeat, it overwrites itself, and we don't get any copies.  We then
# get our final result by joining the keys of the seen hash, which are the
# email addresses, using commas, and put this onto the new_event array.  If
# form data did not have any users selected, we just push the old list onto
# the new array.

		if ($form_data{'notify'} eq "on") {
			@notify_users = split ("\0", $form_data{'mail_choices'});
		}
		if (scalar(@notify_users > 0)) {
			my (@old_users) = split (/,/, $notified);
			my (%seen, $item, $result);
			foreach $item (@notify_users) { $seen{$item} = 1; }
			foreach $item (@old_users) { $seen{$item} = 1; }
			$notified = join(",", (keys(%seen)));
		}
		$linktitle = $form_data{'linktitle'} if ($form_data{'linktitle'} ne "");
		$linkurl = $form_data{'linkurl'} if ($form_data{'linkurl'} ne "");
		if ($linkurl ne "" && linktitle ne "") {
			$linkurl =~ s/\\/\//g;
			unless ($linkurl =~ /^(http|https|ftp)\:\/\//) {
				$linkurl = "http://$linkurl";
			}
		} else {
			$linkurl = "";
			$linktitle = "";
		}

# Okay, we are done updating our event, so we need to write out the information to
# files.  We create our new line by joining the values with "|".  We then get a
# lock file, and open up the new database file, creating it if it doesn't exist,
# appending to it if it does.  We print our new line to the database, close it up,
# release the file lock, and sort the file.

		$new_line = "$day\|$time\|$username\|$mod_item";
		&GetFileLock("$lock_file");
		if ($db_exist) {
			open (DATABASE, ">>$database_file") || &open_error($database_file);
		} else {
			open (DATABASE, ">$database_file") || &open_error($database_file);
		}
		print DATABASE "$new_line\n";
		close (DATABASE);
		&ReleaseFileLock ("$lock_file");
		&sort_events ();

# We now create the event file for the modified event.  Since the information is
# all at hand, we will just clobber the original file in the process of updating
# it, to make this a little easier.  We format our file just as we did in the
# original add event subroutine.

		$new_line = "";
		$new_line = "time->$time\ntimezone->$time_zone\ndurationhrs->$dur_hrs\n";
		$new_line .= "durationmins->$dur_mins\nname->$name\nemail->$email\n";
		$new_line .= "notified->$notified\nlinkurl->$linkurl\nlinktitle->$linktitle\n";
		$new_line .= "location->$location\nsubject->$subject\nbody->$body\n";
		open (EVENTFILE, ">$path_to_events/$mod_item") || &open_error ("event file $mod_item");
		print EVENTFILE "$new_line";
		close (EVENTFILE);

# If we are set up to notify people of these changes, we make our list of people
# to notify, adding the administrator if they have so chosen.

		if ($allow_notify) {
			$to_notify = "$notified";
		}
		if ($notify_event) {
			$to_notify = "$auth_admin_email_address,$to_notify";
		}

# We now send out the notification to all the email addresses in the string.

		if ($to_notify) {
			&notification ($day,$time,$time_zone,$dur_hrs,$dur_mins,
						   $to_notify,$location,$subject,$body,"2");
		}

# Finally, we are done, so we print out a confirmation message to the user,
# and provide a button for them to refresh the calendar.  We of course
# close with the standard footer.

		print qq!
</form><center><h3>Your Event &quot;$subject&quot; has been Modified</h3>
<form method="post" action="$this_script_url" target="$month_frame">
<input type="hidden" name="month" value="$currentmonth">
<input type="hidden" name="year" value="$currentyear">
<input type="hidden" name="session_file" value="$session_file">
<input type="hidden" name="calendar" value="$form_data{'calendar'}">
<input type="submit" name="action" value="Refresh Calendar">
</form></center>!;
	}
	&footer;
}

# SUB SEARCH_FORM #

# If we have called this subroutine, it means the user has requested to
# perform a search, and needs to supply information on it.

sub search_form {
	my ($i,$startyear,$endyear,$month);

# We print out our standard header, and start creating HTML for the
# entire form.  We need to supply a start date for the search, and
# we do that by using our select_a_month and select_a_year subroutines,
# as well as providing a day selector.  We automatically select the current
# day (localtime) for the day value.

	&header("Search for Events");
	print qq!
<center><h3>Search for Events</h3>
<table border="0" cellpadding="2" cellspacing="1"><tr>
<td align="right"><font size="2"><b>Start Search&#58;</b></font></td><td>!;
	&select_a_month;
	print "\&nbsp\;<select name=\"startday\">\n";
	for ($i = 1; $i < 32; $i++) {
		if ($i eq "$ltday") {
			print "<option selected value=\"$i\">$i\n";
		} else {
			print "<option value=\"$i\">$i\n";
		}
	}
	print "</select><b>,</b>\&nbsp\;\&nbsp\;";
	&select_a_year;

# Now we need our end date.  We can't use select_a_month and select_a_year
# again, because then the selectors would have the same name as the start
# date selectors, and we wouldn't get anywhere.  So we need to create
# them manually.  We basically copy the code out of the two subroutines,
# and simply supply a different name for the selectors.  See the comments
# in these subroutines if you want to know what is happening here.

	print qq!
</td></tr>
<tr><td align="right"><font size="2"><b>End Search&#58;</b></font></td><td>
<select name="endmonth">!;
	foreach $month (sort {$a <=> $b} (keys %month_hash)) {
		if ($month ne "$currentmonth") {
			print "<option value=\"$month\">$month_hash{$month}\n";
		} else {
			print "<option selected value=\"$month\">$month_hash{$month}\n";
		}
	}
	print "</select>\n";
	print "\&nbsp\;<select name=\"endday\">\n";
	for ($i = 1; $i < 32; $i++) {
		if ($i eq "$ltday") {
			print "<option selected value=\"$i\">$i\n";
		} else {
			print "<option value=\"$i\">$i\n";
		}
	}
	print "</select><b>,</b>\&nbsp\;\&nbsp\;";
	print "<select name=\"endyear\">\n";
	$startyear = ($ltyear <= $currentyear ? $ltyear : $currentyear);
	$endyear = ($currentyear <= $greatest_year ? $greatest_year : $currentyear);
	for ($i = $startyear; $i <= $endyear; $i++) {
		if ($i eq "$currentyear") {
			print "<option selected value=\"$i\">$i\n";
		} else {
			print "<option value=\"$i\">$i\n";
		}
	}
	print "</select>\n";

# Now we need an input item for the keywords to search on, radio buttons
# to decide whether we want to do an AND or and OR logical search, and
# checkboxes to select which fields we want to search.  The choices are
# Subject, Body, and Location.  We then finish up our form with the
# proper buttons.

	print qq!
</td></tr><tr><td align="right"><font size="2"><b>Keywords&#58;</b></font></td>
<td><input type="text" name="keywords" size="30" maxlength="60"><br>
<font size="1">Enter keywords separated by spaces.</font></td></tr>
<tr><td align="right"><font size="2"><b>Match&#58;</b></font></td>
<td><font size="2"><b><input type="radio" name="logic" value="all">All
<input type="radio" name="logic" value="any" checked>Any</b></font></td></tr>
<tr><td align="right"><font size="2"><b>Search In&#58;</b></font></td>
<td><font size="2"><b><input type="checkbox" name="fields" value="body" checked>Body
<input type="checkbox" name="fields" value="subject">Subject
<input type="checkbox" name="fields" value="location">Location</b></font></td></tr>
</table><p>
<input type="submit" name="action" value="Find Events">
<input type="reset" value="Clear This Form">!;

# We are done with this form, so we print out our online help link if we are
# using online help, and close with the standard footer.

	if ($use_help) {
		print "<p>";
		&help_link ("10");
	}
	print "</center></form>";
	&footer;
}

# SUB SEARCH_EVENTS #

# If we have called this subroutine, it means the user has entered their
# search criteria, and is ready to see some results.

sub search_events {
	my (@fields, $logic, $match_found, $search_month, $search_year, $end_file);
	my ($start_num, $end_num, $srch_str, $db_file, $day_num, $i);
	my (@keywords, $keywords, @results, $day, $time, $user, $id, $and_res, $link);
	my ($time_zone, $dur_hrs, $dur_mins, $name, $email, $notified);
	my ($linkurl, $linktitle, $location, $subject, $body);

# We initialize some of our variables with the data entered in the form.
# We get which fields the user wants to search in, the logic they wish
# to use, the keywords to search for, and the date range to use for the
# search.  We concatenate the year, month, and day for both the start and
# end dates, and we also save some information on our ending file.

	@fields = split(/\0/, $form_data{'fields'});
	$logic = $form_data{'logic'};
	@keywords = split(/ /, $form_data{'keywords'});
	$keywords = join("\|", @keywords);
	$start_num = "$form_data{'year'}".sprintf("%.2d", $form_data{'month'});
	$start_num .= sprintf("%.2d", $form_data{'startday'});
	$end_num = "$form_data{'endyear'}".sprintf("%.2d", $form_data{'endmonth'});
	$end_file = $end_num;
	$end_num .= sprintf("%.2d", $form_data{'endday'});

# Of course, we have to do some error checking.  The first if statement
# is checking to see if the user entered an end date that is before the
# start date.  The next check is to see if the user did not select any
# fields to search.  The next check is to see if the user did not enter
# any keywords to search for.  If any of the logic statements evaluate
# to true, we have an error condition, and won't go into the search routine.

	if ( $end_num lt $start_num ) {
		&header ("Invalid Search Date Range");
		print qq!
</form><center><h3>Search Date Range Error</h3></center>
<blockquote>
I'm sorry, but you entered an End Date that is earlier than the Start Date
for your search.  Please hit your back button and try again.</blockquote>!;
		&footer;
	} elsif (scalar(@fields) < 1) {
		&header ("No Search Fields Selected");
		print qq!
</form><center><h3>No Search Fields Error</h3></center>
<blockquote>
I'm sorry, but you did not select any fields to be searched.  Please hit your
back button and try again.</blockquote>!;
		&footer;
	} elsif (scalar(@keywords) < 1) {
		&header ("No Keywords Entered");
		print qq!
</form><center><h3>No Keywords Error</h3></center>
<blockquote>
I'm sorry, but you did not enter any keywords for which to search.  Please hit your
back button and try again.</blockquote>!;
		&footer;
	} else {

# If we have made it through all of our error checks, we are ready to start our
# search.  We initialize our search_year and search_month variables with the
# currentyear and currentmonth, as they hold the values for the start year and
# month for the search.  We make a new base file out of these, and then a
# new db_file that we will search for.  This is all so we have a more efficient
# loop through the start and end search dates.

		$search_year = $currentyear;
		$search_month = $currentmonth;
		$base_file = "$currentyear".sprintf("%.2d", $currentmonth);
		$base_file =~ /^(\d{6})/o;
		$base_file = $1;
		$db_file = "$calendar_type/$base_file.events";

# We now make sure that our bse_file is less than or equal to our end_file.  This
# is to handle the conditions where the user wants to search in only one month, or
# wants to search through many months.  This one statement will handle both conditions.
# We will continue going through our event files until this is false.

		while ( $base_file <= $end_file ) {
			if ( -e $db_file ) {

# If the db_file exists, we open up the file, then start reading through it
# one line at a time.  We remove the new line character from our id number for
# each event, then, on each pass, we initialize our search variables, $srch_str,
# $match_found, and $and_res.  This is handled on one line.  We then get the
# day number set to our base file plus the day number for the event.

				open (DATA, "$db_file") || &open_error ( $db_file );
				while (<DATA>) {
					($day,$time,$user,$id) = split(/\|/, $_);
					chomp ($id);
					$srch_str = "";	$match_found = 0; $and_res = 0;
					$day_num = "$base_file".sprintf("%.2d", $day);

# If our day number is greater than or equal to our start number and it is also
# less than or equal to our end number, we have an event that we want to search
# through, so we get the event information using get_event_info, and then
# use the information found therein to make our search string ($srch_str) by
# concatenating each item the user has asked to search through onto this string.

					if ( ($day_num ge $start_num) && ($day_num le $end_num) ) {
						($time,$time_zone,$dur_hrs,$dur_mins,$name,$email,$notified,
			 		 	$linkurl,$linktitle,$location,$subject,$body) = &get_event_info("$id");
						foreach $i (@fields) {
							if ($i eq "subject") { $srch_str .= " $subject"; }
							elsif ($i eq "location") { $srch_str .= " $location"; }
							elsif ($i eq "body") { $srch_str .= " $body"; }
						}

# If the user has selected any as the logic type, we do a search on our keywords,
# using a regular expression with each word separated by the or symbol in regular
# expressions (|).  That is why above we joined our keywords with the "|" symbol.
# If we get a match, we set our $match_found flag to true.
# Else, if the user has selected all as the logic type, we loop through each keyword
# in our keyword array.  For each keyword that we find in the search string, using
# regular expressions, we add one to the $and_res variable.  At the end of the
# loop, we determine if $and_res equals the number of keywords we entered.  If it
# does, we found each of the keywords in our search string, and so we set our
# $match_found flag to true.

						if ( $logic eq "any" ) {
							if ( $srch_str =~ /\b($keywords)\b/i ) {$match_found = 1;}
						} elsif ( $logic eq "all" ) {
							foreach $i (@keywords) {$and_res++ if ($srch_str =~ /\b($i)\b/i);}
							if ( scalar(@keywords) == $and_res ) {$match_found = 1;}
						}

# If we made a match on the current event, as determined by our $match_found flag being
# set to 1, we create a link to this event, formatted to use our javascript function
# in the header of each HTML page, and including all the information that will be
# required by the view_search_sub above.  We then push it onto our results array for
# later printing.

						if ( $match_found ) {
							$link = "<font size=\"2\"><b><a href=\"javascript\:openNew('$this_script_url?";
							$link .= "calendar=$form_data{'calendar'}\&session_file=$session_file";
							$link .= "\&action=view_search\&month=$search_month\&year=$search_year";
							$link .= "\&id=$id\&day=$day')\">";
							$link .= "view:</a>\&nbsp\;\&nbsp\;$subject</b></font>";
							$link .= "<font size=\"1\">\&nbsp\;\&nbsp\;--\&nbsp\;\&nbsp\;$month_hash{$search_month} ";
							$link .= "$day, $search_year";
							if ($time =~ /\d+/) { $link .= " at $TIME{$time}"; }
							else { $link .= " ( All Day )"; }
							$link .= "</font><p>";
							push (@results, $link);
						}
					}
				}

# Once we are done with the current db_file, we close it.

				close (DATA);
			}

# We now increment our search_month variable, correcting the search_year and
# search_month if we go over 12.  Then we concatenate it into a new base_file
# and a new db_file for our next pass through the while loop above.  Thus, we
# will efficiently cover all of our months to search through.

			$search_month++;
			if ($search_month > 12) { $search_month = 1; $search_year++; }
			$base_file = "$search_year".sprintf("%.2d", $search_month);
			$base_file =~ /^(\d{6})/o;
			$base_file = $1;
			$db_file = "$calendar_type/$base_file.events";
		}

# Once the while loop quits, we are done searching through files, so we print out
# the results to the user.  We provide some basic HTML to let them know what we
# are showing them.  Then, if our results array contains one or more items, we
# print each of them out.  Else, we let the user know that we didn't find any
# events matching their criteria.

		&header("Search Results");
		print qq!
</form><center><h3>Search Results</h3></center>
<blockquote>Below are the results from your search.  Click on a link to get detailed information
regarding the event.</blockquote><ul>\n!;
		if ( scalar(@results) > 0 ) {
			foreach $i (@results) {
				print "$i\n";
			}
		} else {
			print "<b>No Events Matched Your Search Criteria.</b><p>";
		}
		print "</ul>";

# Of course, we end by printing out a help link if we are using online help,
# and then print out the standard footer, and we are done.

		if ($use_help) {
			print "<p><center>";
			&help_link ("12");
			print "</center>";
		}
		&footer;
	}
}

# SUB MAKE_MONTH_ARRAY #

# This subroutine is used to create an array formatted to conform to
# a month display.

sub make_month_array {
	my($juldate)  = $_[0];
	my(@month_days) = ('0','31','28','31','30','31','30','31','31','30','31','30','31');
	my(@myarray, $numdays, $remain, $x);

# Get the month, day, year, and first week day of the julian date passed
# by using the jdate subroutine.

	my($month,$day,$year,$firstweekday) = &jdate($juldate);

# Get the number of days in the month from the month_days array above, if
# we are not in February.  If we are in February, determine if we are in
# a leap year.  If we are not, we have 28 days, otherwise we have 29.

	if ($month != 2) {
		$numdays = $month_days[$month];
	} else {
		unless (($year % 4 == 0 && $year % 100 != 0) ||
				($year % 400 == 0)) {
			$numdays = 28;
		} else { $numdays = 29; }
	}

# Pad the beginning of the array with blanks until we get to the first
# week day for the month.

	for ($x = 0; $x < $firstweekday; $x++) { $myarray[$x] = " "; }

# Now that we are into the month, assign the day number into each cell of the
# array until we get above the number of days in the month.

	for ($x = 1; $x <= $numdays; $x++) { $myarray[$x + $firstweekday - 1] = $x; }

# Find out how many indices we are short of an even multiple of 7.
# If we are not an even multiple of 7, pad the end of the array
# with blanks.

	$remain = scalar(@myarray) % 7;
	unless ($remain == 0) {
		for ($remain; $remain < 7; $remain++) { push (@myarray, " "); }
	}

# We are done, so return the formatted array.

	return (@myarray);
}

# SUB CGIREQUIRE #

# This subroutine takes a list of files with path information that are needed
# by this script, and attempts to require them.

sub CgiRequire {
	my (@require_files) = @_;
	my ($file);

# Check to see if each file exists and is readable.
# If it is, require it.  If it is not, provide an error
# message for the file we could not require, and exit the program.

	foreach $file (@require_files) {
		if (-e "$file" && -r "$file") {
			require "$file";
		} else {
			&header("Require File Error");
			print qq!
I'm sorry, I was not able to open $file.  Would you
please check to make sure that you gave me a valid filename
and that the permissions on $file are set to allow me
access?</form></body></html>!;
			exit;
		}
	}
}

# SUB SELECT_A_MONTH

# This subroutine generates a drop selector on the form to allow
# the user to pick a specific month.

sub select_a_month {
	my ($month);
	print "<select name=\"month\">\n";

# After we have started the select tag, go through the sorted (numerically)
# keys of %month_hash.  If the month is not equal to the current month, add
# the value as an option.  If it is equal to the current month, set it as
# the selected option. Then close out hte select tag.

	foreach $month (sort {$a <=> $b} (keys %month_hash)) {
		if ($month ne "$currentmonth") {
			print "<option value=\"$month\">$month_hash{$month}\n";
		} else {
			print "<option selected value=\"$month\">$month_hash{$month}\n";
		}
	}
	print "</select>\n";
}

# SUB SELECT_A_YEAR #

# This subroutine generates a drop selector on the form to allow
# the user to pick a specific year.

sub select_a_year {
	my ($startyear,$endyear,$i);
	print "<select name=\"year\">\n";

# After we have started the HTML select tag, we determine our startyear
# and endyear.  Note that this format allows us to run off the edge of
# our normal limits without messing up the interface.

	$startyear = ($ltyear <= $currentyear ? $ltyear : $currentyear);
	$endyear = ($currentyear <= $greatest_year ? $greatest_year : $currentyear);

# We now fill in the option tags from the startyear to the endyear.  If
# we hit the currentyear, we set it to selected to begin with.  We then
# close the select tag.

	for ($i = $startyear; $i <= $endyear; $i++) {
		if ($i ne "$currentyear") {
			print "<option value=\"$i\">$i\n";
		} else {
			print "<option selected value=\"$i\">$i\n";
		}
	}
	print "</select>\n";
}

# SUB EVENT_TABLE #

# This subroutine is used to create a nicely formatted table of events
# for use in the modify and delete event form subroutines.
# We pass it one paramter which defines whether it should be a modify
# table or a delete table.

sub event_table {
	my ($modify) = $_[0];
	my ($value,$day,$username,$name,$email,$subject);
	my ($time,$time_zone,$location,$body,$dur_hrs,$dur_mins,$id);
	my ($item_found,$table,$linkurl,$linktitle,$notified);

# Print out some HTML to let the user know which type of form this is.

	print "<center>\n";
	if ($modify) {
		print "<h3>Modify - $current_month_name $form_data{'day'}, $currentyear</h3>\n";
	} else {
		print "<h3>Delete Events - $current_month_name, $currentyear</h3>\n";
	}

# If online help has been enabled, print out the proper help topic link.

	if ($use_help) {
		print "<p>";
		if ($modify) {
			&help_link("5");
		} else {
			&help_link("6");
		}
	}

# Start the table.  We fill the top row with the headings for the columns, and add in
# the item column as the first.  We fill in the other columns using a foreach loop
# and the @field_names array.

	$table = "";
	$table .= "<table border=\"2\" cellspacing=\"1\" cellpadding=\"2\">";
	$table .= "\n<tr>\n";
	$table .= "<th bgcolor=$apptcol valign=\"bottom\"><font color=$hitxt size=\"2\">Item</font></th>\n";
	foreach $value (@field_names) {
		$table .= "<th bgcolor=$apptcol valign=\"bottom\"><font color=$hitxt size=\"2\">$value</font></th>\n";
	}
	$table .= "</tr>\n";

# We now open up the database file.

	open (DAYFILE, "$database_file") || &open_error($database_file);
	while (<DAYFILE>) {

# We read through the file one line at a time, stripping off the newline
# character.  We then split up the row into variables which we will use
# in just a minute.

		chomp $_;
		($day, $time, $username, $id) = split (/\|/,$_);

# If the day is equal to the form data day, or if this is not a modify
# table, AND if the username of the event matches the session username
# or the administrator is looking at it, we have found an event.

		if (($day eq "$form_data{'day'}" || !$modify) &&
			( $session_username eq "$username" || $session_group eq "admin" )) {
			$item_found = "yes";

# We have found an event, so we need to get the information about it by
# using the get_event_info subroutine.  We then format our time_zone
# variable, and start adding to the table.  We add a cell that spans two
# rows to hold a radion button if it is a modify table, or a checkbox if
# it is a delete table.  These are keyed to the event id number.

			($time,$time_zone,$dur_hrs,$dur_mins,$name,$email,$notified,
			 $linkurl,$linktitle,$location,$subject,$body) = &get_event_info("$id");
			$time_zone = ($use_time_zones ? " $time_zone" : "");
			$table .= "<tr>\n";
			$table .= "<td align=\"center\" rowspan=\"2\">";
			$table .= "<input type=";
			if ($modify) {
				$table .= "\"radio\" ";
			} else {
				$table .= "\"checkbox\" ";
			}
			$table .= "name=\"item_to_mod_del\" value=\"$id\"></td>\n";

# We now print out information about the event in a compact format for reference.

			$table .= "<td align=\"center\"><font size=\"2\">";
			$table .= "$currentmonth/$day/$currentyear";
			if ($dur_hrs || $dur_mins) {
				$table .= " - $TIME{$time}$time_zone";
			}
			$table .= "</font></td>\n";
			$table .= "<td align=\"center\"><font size=\"2\">$dur_hrs hrs, $dur_mins mins</font></td>";
			$table .= "\n<td align=\"center\"><font size=\"2\">$subject</font></td>\n";
			$table .= "<td align=\"center\"><font size=\"2\">$location</font></td></tr>\n";
			$table .= "<tr><td colspan=\"4\"><font size=\"2\">$body";
			if ($allow_links && $linktitle && $linkurl) {
				$table .= "<p>$linktitle - $linkurl";
			}
			$table .= "</font></td></tr>\n";
		}
	}
	$table .= "</table><p>\n";
	close (DAYFILE);

# Once we have finished going through the table, we check our item_found flag.
# If we haven't found any items, we let the user know that, otherwise, we print
# out the table.

	if ($item_found ne "yes") {
		print qq!
</center><blockquote>
I'm sorry, no items were found that were posted by you, so there is nothing
for you to modify.</blockquote>!;
		&footer;
		exit;
	} else {
		print $table;
	}
}

# SUB SUBMISSION_FORM #

# This subroutine is used to generate the form used to add or modify an event,
# and thus takes a parameter to determine which type of form it is generating.

sub submission_form {
	my ($type_of_form) = $_[0];
	my ($i,$name,$email,$temp_day);

# If we are using online help, we print out the help topic link.

	if ($use_help) {
		unless ($type_of_form eq "modify") {
			print "<center>";
			&help_link ("4");
			print "</center>";
		}
	}

# We now start to print out the table that will line up our form.

	print "<table border=\"0\" cellspacing=\"2\" cellpadding=\"2\">",
		  "<tr><td align=\"right\"><font size=\"2\"><b>Contact\&\#58\;</b></font></td>";

# If our session name is not blank, that is, we are using some form or verification,
# either cgi or server based, then we automatically fill in the information for
# the poster's name and email address.  Otherwise, we provide text fields for the
# user to type in their name and email address.

	if ($session_name ne "") {
		print qq!
<td valign="bottom">$session_name</td></tr>
<tr><td align="right"><font size="2"><b>Email&#58;</b></font></td><td>$session_email
</td></tr>!;
	} else {
		print qq!
<td valign="bottom"><input type="text" name="real_name" size="20" maxlength="30">
</td></tr><tr><td align="right"><font size="2"><b>Email&#58;</b></font></td>
<td><input type="text" name="email" size="20" maxlength="30"></td></tr>!;
	}

# Now we provide an input field to type in the subject of the event, and
# start the event date information.

	print qq!
<tr><td align="right"><font size="2"><b>Subject&#58;</b></font></td>
<td><input type="text" name="subject" size="30" maxlength="60"></TD>
</tr><tr><td align="right"><font size="2"><b>When&#58;</b></font></td><td>!;

# To get all of the date information, we use the select_a_month subroutine to
# get a month selector, then we create a selector for the day, numbering 1
# through 31, with the current day selected, and then use the select_a_year
# subroutine to provide a year selector.

	&select_a_month;
	if ($form_data{'day'}) {
		$temp_day = $form_data{'day'};
	} else {
		$temp_day = $ltday;
	}
	print "<select name=\"day\">\n";
	for ($i = 1; $i < 32; $i++) {
		if ($i eq "$temp_day") {
			print "<option selected value=\"$i\">$i\n";
		} else {
			print "<option value=\"$i\">$i\n";
		}
	}
	print "</select><b>,</b>\&nbsp\;\&nbsp\;";
	&select_a_year;

# We now prompt for the start time of the event.  We provide a selector
# keyed to our %TIME hash, but if we are using a modify item form, we
# also provide a blank option to not change the time of the event.

	print qq!
</td></tr><tr><td align="right"><font size="2"><b>Start Time&#58;</b></font></td>
<td><select name="time">!;
	if ($type_of_form eq "modify") {
		print "<option value=\"\">Don't Change Time\n";
	}
	foreach $i (sort (keys %TIME)) {
		if ($i ne "09:00") {
			print "<option value=\"$i\">$TIME{$i}\n";
		} else {
			if ($type_of_form ne "modify") {
				print "<option selected value=\"$i\">$TIME{$i}\n";
			} else {
				print "<option value=\"$i\">$TIME{$i}\n";
			}
		}
	}
	print "</select>\n";

# If we are using time zone information, we provide a selector for the
# user to pick a time zone.  If we are using a modify form, we also provide
# a blank to avoid changing the time zone.

	if ($use_time_zones) {
		print "<b>\&nbsp\;\&\#45\;\&nbsp\;</b><select name=\"time_zone\">";
		if ($type_of_form eq "modify") {
			print "<option value=\"\">Don't Change Time Zone\n";
		}
		foreach $i (@time_zone_values) {
			print "<option value=\"$i\">$i\n";
		}
		print "</select>";
	}

# We now provide selectors for the user to enter the duration of the event
# in hours and minutes.  We provide blanks for each in the case of a modify
# form, to avoid changing the duration.

		print qq!
</td></tr><tr><td align="right"><font size="2"><b>Duration\&\#58\;</b>
</font></td><td><select name="dur_hrs">!;
	if ($type_of_form eq "modify") {
		print "<option value=\"\">Don't Change\n";
	}
	foreach $i (@hour_values) {
		print "<option value=\"$i\">$i\n";
	}
	print qq!
</select><font size="2"><b>\&nbsp;\&nbsp;hours, \&nbsp;</b></font>
<select name="dur_mins">!;
	if ($type_of_form eq "modify") {
		print "<option value=\"\">Don't Change\n";
	}
	foreach $i (@mins_values) {
		print "<option value=\"$i\">$i\n";
	}
	print "</select><font size=\"2\"><b>\&nbsp;\&nbsp;mins</b></font></td></tr>\n";

# We now provide an input item for entering the location of the event, and a
# textarea box to enter the body information of the event.

	print qq!
<tr><td align="right"><font size="2"><b>Location&#58;</b></font></td>
<td><input type="text" name="location" size="30" maxlength="60"></td></tr>
<tr><td align="right" valign="top"><font size="2"><b>Body&#58;</b></font></td>
<td align="left"><textarea wrap="virtual" name="body" rows="4" cols="30"></textarea>
</td></tr>!;

# If we are allowing web links in the calendar, we provide input items to
# enter the link title and link url to be used.

	if ($allow_links) {
		print qq!
<tr><td align="right"><font size="2"><b>Link Title\&\#58;</b></font></td>
<td><input type="text" name="linktitle" size="30" maxlength="30">
</td></tr><tr><td align="right"><font size="2"><b>Link URL\&\#58;</b></font></td>
<td><input type="text" name="linkurl" size="30" maxlength="80"></td></tr>!;
	}

# If we are allowing notifications, we provide a checkbox to select that we
# do want to notify people, and then a multiple selector that is created by
# opening the authorized users file and reading all the lines in there.  For
# each entry, we use the name of the user as the item to show up in the
# selector, and their email address for the value to be returned if they are
# selected.  We then close the file, and print out information on how to
# select multiple people to notify.

	if ($allow_notify) {
		print qq!
<tr><td align="right" valign="top"><font size="2"><b>Notify\&\#58;</b></font></td>
<td valign="top"><input type="checkbox" name="notify" value="on"><font size="1">Check
box to notify, via email, selected people below.</font><br>
<select name="mail_choices" size="2" multiple>!;
		open (AUTHFILE, "$auth_user_file") || &open_error($auth_user_file);
		while (<AUTHFILE>) {
			chomp $_;
			($name, $email) = (split (/\|/,$_))[3,4];
			print "<option value=\"$email\">$name\n";
		}
		close (AUTHFILE);
		print qq!
</select><br><font size="1">Hold down Ctrl key to select multiple.</font></td></tr>!;
	}

# We now provide some notes to the user regarding the properties of the Body textarea,
# since many people want to hit the return key at the right margin of the
# textarea rather than letting it wrap automatically.

	print qq!
</table>
<font size="1"><blockquote>Note: In the &quot;Body&quot; text box above, do not press the
return or enter key unless you want to break a line in the final calendar entry. The box
will automatically wrap your text for continuous sentences.</blockquote></font>!;
}

# SUB HEADER #

# This subroutine takes a title as an argument.  It then generates the
# content type information so the browser knows what it is receiving, and
# then opens up the HTML page.  It provides a javascript function that will
# be used by the help files and the search routine to display information.
# It also starts the standard form that will be used on most every page.

sub header {
	my ($title) = $_[0];
	if ($title eq "") {
		$title = "$cal_name Calendar";
	}
	print "Content-type: text/html\n\n";
	print "<html><head><title>$title</title>";
		print qq!
<script language="JavaScript" type="text/javascript">
<\!--
    function openNew(url) {
        var win = window.open(url, "fc_info", "scrollbars,height=225,width=400");
        win.focus();
    }
//-->
</script>\n!;
	print qq!
</head><body$bodytag>
$basefont_tag
<form method="post" action="$this_script_url">
<input type="hidden" name="session_file" value="$session_file">
<input type="hidden" name="calendar" value="$form_data{'calendar'}">!;
}

# SUB FOOTER #

# This subroutine is used to generate a standard footer for each HTML
# page, and properly close the HTML.

sub footer {
	print qq!
<p><font size="1">
For comments or questions, contact
<a href="mailto:$auth_admin_email_address?subject=Help">Calendar Administrator</a>
</font></body></html>!;
}

# SUB PRINT_EVENT #

# This subroutine prints out the information for an event in the specified
# format.  It is called from three other subroutines.

sub print_event {
	my ($event) = $_[0];
	my ($time,$time_zone,$dur_hrs,$dur_mins,$name,$email,$notified);
	my ($linkurl,$linktitle,$location,$subject,$body,$end_time);
	my ($mmn,$mh,$md,$mm,$myr,$mtime,$mtstr,$ampm);

# We first gather all of the information on the event that was passed to us,
# and then format the time_zone variable and the end_time variable for display.

	($time,$time_zone,$dur_hrs,$dur_mins,$name,$email,$notified,
	 $linkurl,$linktitle,$location,$subject,$body) = &get_event_info("$event");

	$time_zone = (($use_time_zones && $time_zone) ? " \( $time_zone \)" : "");
	if ($dur_hrs || $dur_mins) {
		$end_time = &get_end_time($time,$dur_hrs,$dur_mins);
	}

# This section of code gets the time that the event file was last modified, so
# we can display this with the event for informational purposes.  After we get
# the time, which is provided in epoch seconds by stat, we format it for printing.

	$mtime = (stat("$path_to_events/$event"))[9];
	($mmn,$mh,$md,$mm,$myr) = (localtime($mtime + ($time_offset * 3600)))[1..5];
	$myr += 1900;
	$mm = $month_hash{$mm + 1};
	$ampm = "am";
	if ($mh >= 12 ) {
		$mh -= 12;
		$ampm = "pm";
	}
	if ($mh == 0) { $mh = 12; }
	$mtstr = "$mm $md, $myr, at $mh\:".sprintf("%.2d", $mmn)." $ampm";

# Now that we have all the information on the event, we need to print it out.
# The following lines of code do just that, printing out the HTML that formats
# the event information.

	print qq!
<font color=$subjcol size="+1"><b>$subject</b></font><table>
<tr><td align="right" width="60"><font color=$timecol size="1">Location&#58;</font></td>
<td><font color=$timecol size="1">$location</font></td></tr>!;
	if ($end_time) {
		print qq!
<tr><td align="right" width="60"><font color=$timecol size="1">Time&#58;</font></td>
<td><font color=$timecol size="1">$TIME{$time} - $TIME{$end_time}$time_zone</font></td></tr>!;
	}
	print qq!
</table><blockquote>$body</blockquote>
<font size="1"><i>For further information contact </i>
<a href="mailto:$email?subject=$subject">$name</a>!;

# At the end of the print, we need to do special formatting depending on whether
# we are allowing off site links to be posted to the event, and if one is present.
# If we answer yes to all of these, we add on the link information, formatting it
# so that we open a new browser to view the link.  Otherwise, we just finish up
# the closing line for the event.

	if ($allow_links && $linktitle && $linkurl) {
		print "<i> or go to </i>",
			  "<a href=\"$linkurl\" target=\"fc_new\">$linktitle</a>";
	}
	print ".<br><i>Last Updated\: $mtstr ( Server Time )</i></font>";
}
			

# SUB GET_EVENT_INFO #

# This subroutine returns the information from an event file associated with an
# id number.  Note that we apply special formatting to the file when we create it,
# and place it in the same order, so that when we call this subroutine it is
# returned in the same order every time.  Thus, if you make modifications to what
# data is stored in this file, be sure to get the insertion/extraction order
# correct!

sub get_event_info {
	my ($filename) = $_[0];
	my (@event_array);

# We open up the file, then read through it one line at a time.  If the line starts
# with one of the tags that we have defined, we push what it "points to" onto the
# array that we will return.

	open (EVENTFILE, "$path_to_events/$filename") || &open_error("event file $filename");
	while (<EVENTFILE>) {
		   if (/^time->(.*)/i)			{ push (@event_array, $1); }
		elsif (/^timezone->(.*)/i)		{ push (@event_array, $1); }
		elsif (/^durationhrs->(.*)/i)	{ push (@event_array, $1); }
		elsif (/^durationmins->(.*)/i)	{ push (@event_array, $1); }
		elsif (/^name->(.*)/i)			{ push (@event_array, $1); }
		elsif (/^email->(.*)/i)			{ push (@event_array, $1); }
		elsif (/^notified->(.*)/i)		{ push (@event_array, $1); }
		elsif (/^linkurl->(.*)/i)		{ push (@event_array, $1); }
		elsif (/^linktitle->(.*)/i)		{ push (@event_array, $1); }
		elsif (/^location->(.*)/i)		{ push (@event_array, $1); }
		elsif (/^subject->(.*)/i)		{ push (@event_array, $1); }
		elsif (/^body->(.*)/i)			{ push (@event_array, $1); }
	}
	close (EVENTFILE);

# At the end of the file, we close it, then chomp the entire array, since
# each item has a trailing new line character.  We are then done, so we
# return the array.

	chomp (@event_array);
	return (@event_array);
}

# SUB GET_END_TIME #

# This subroutine takes a beginning time and duration and returns a
# properly formatted end time.

sub get_end_time {
	my ($time,$dur_hrs,$dur_mins) = @_;
	my ($end_hrs,$end_mins,$end_time);

# Initialize the end_hrs and end_mins by splitting the start time
# at the :.  We then increase the minutes by the duration minutes.
# If they are greater than 60, we add one to end_hrs, and subtract
# 60 off of end_mins.  Then we add the duration hours to end_hrs,
# and correct for being greater than 24 if necessary.  We then
# format the time correctly, and return it.

	($end_hrs,$end_mins) = split(/:/, $time);
	$end_mins += $dur_mins;
	if ($end_mins >= 60) { $end_hrs++; $end_mins -= 60; }
	$end_hrs += $dur_hrs;
	if ($end_hrs >= 24) { $end_hrs -= 24; }
	$end_time = sprintf("%.2d", $end_hrs).":".sprintf("%.2d", $end_mins);
	return ($end_time);
}

# SUB NOTIFICATION #

# This subroutine handles all of the notification services for this script,
# formatting the messages properly before sending them to sendmail.

sub notification {
	my($day,$time,$time_zone,$dur_hrs,$dur_mins,$notified,
	   $location,$subject,$body,$type) = @_;
	my($notify_user,@notified,$msg_subject,$message,$type_word,$end_time);

# We start off by splitting our comma separated list of email addresses into
# an array.  We then use the type variable that was passed to decide whether
# we are sending out a new event notice, a deleted event notice, or a modified
# event notice.

	@notified = split (/,/, $notified);
	if ($type == 1) {
		$type_word = "Added";
	} elsif ($type == 0) {
		$type_word = "Deleted";
	} elsif ($type == 2) {
		$type_word = "Modified";
	}

# We format the time_zone and end_time variables.

	$time_zone = ($use_time_zones ? " - $time_zone" : "");
	if ($dur_hrs || $dur_mins) {
		$end_time = &get_end_time($time,$dur_hrs,$dur_mins);
	}

# We now require our mail library for using sendmail.

	&CgiRequire("$lib/mail-lib.pl");

# The following lines format the message to be sent out.  Since this isn't
# an HTML message, we have to modify some variables to compensate for HTML
# tags.

	$body =~ s/<P>/\n\n/gi;
	$body =~ s/<BR>/\n/gi;
	$msg_subject = "Event $type_word - $cal_name Calendar";
	$message = "The following event in the $cal_name Calendar was ".lcfirst("$type_word").".\n($html_url)\n\n";
	$message .= "    Subject:  $subject\n";
	$message .= sprintf ("%8s", $type_word)." By:  $session_name ($session_email)\n";
	$message .= "Event  Time:  $currentmonth/$day/$currentyear";
	if ($end_time) {
		$message .= " from $TIME{$time} to $TIME{$end_time}$time_zone\n";
	} else {
		$message .= " ( All Day )\n";
	}
	$message .= "   Location:  $location\n\n";
	$message .= "$body\n";

# Finally, after getting our message together, we send the notification out to
# each person in the notified array.

	foreach $notify_user (@notified) {
		&send_mail ($session_email, $notify_user, $msg_subject, $message);
	}
}

# SUB LAST_DAY #

# Quite often we need to know what the last day of a month is, for error checking
# purposes.

sub last_day {
	my($ldmonth, $ldyear) = @_;
	my(@month_days) = ('0','31','28','31','30','31','30','31','31','30','31','30','31');
	my($numdays);

# If we are not in February, we know from the above array what the number of days
# in the month is, so we set $numdays to that value.  However, if we are in February,
# we first have to check for a leap year, which is what the convoluted logic statement
# below does.  This is the correct algorithm for checking for leap year.  If it is
# a leap year, we set $numdays to 29, else, it is set to 28.

	if ($ldmonth != 2) {
		$numdays = $month_days[$ldmonth];
	} else {
		unless (($ldyear % 4 == 0 && $ldyear % 100 != 0) ||
				($ldyear % 400 == 0)) {
			$numdays = 28;
		} else { $numdays = 29; }
	}

# We are done, so return the number of days in the month.

	return ($numdays);
}

# SUB INVALID_DATE #

# If someone has tried to add or modify an event, placing it on a day
# that does not occur for the given month and year, we do not add
# the event.  Instead, we send an error message telling them that
# the date is invalid, and exit the program.

sub invalid_date {
	my ($last_day,$chosen_day) = @_;
	print qq!
</form><center><h3>Invalid Day for Event</h3></center><blockquote>
I'm sorry, but $current_month_name only has $last_day days.
You tried to add an event to day number $chosen_day.
Please hit your browser's back button, and choose a valid day.</blockquote>!;
	&footer;
	exit;
}

# SUB HELP_LINK #

# This subroutine provides a nicely formatted help link, tying it into the javascript
# function we have defined in our header, given a help topic that will be accessed
# by the link.

sub help_link {
	my ($help_id) = $_[0];
	print qq!
<a href="javascript:openNew('$help_script?config_file=$help_setup&help_topic=$help_id')">
<b>H&nbsp;E&nbsp;L&nbsp;P</b></a>!;
}

# SUB SORT_EVENTS #

# This routine is used to sort the events database files when they have been
# modified.

sub sort_events {
	my (@database_rows, @sorted_temp_database, $row);

# First we get the file lock for the database file we will be sorting.
# We then open the file and read it into an array that we will use
# to sort the items with.  Then we close the file.

	&GetFileLock ("$lock_file");
	open (DATABASE, "$database_file") || &open_error($database_file);
	while (<DATABASE>) {
		push (@database_rows, $_);
	}
	close (DATABASE);

# We now sort the array, modifying the normal Perl sort routine to
# with a custom sort definition found in sub date_sort.

	@sorted_temp_database = sort date_sort (@database_rows);

# We now open up the temp file for the database file we are working
# with, and write the sorted database file to it.

	open (TEMPFILE, ">$temp_file") || &open_error($temp_file);
	foreach $row (@sorted_temp_database) {
		print TEMPFILE "$row";
	}
	close (TEMPFILE);

# We now remove the original database file, and replace it with the
# renamed temp file which contains sorted contents.  We release the
# file lock when we are done.

	unlink ("$database_file");
	rename ($temp_file, $database_file);
	&ReleaseFileLock ("$lock_file");
}

# SUB DATE_SORT #

# This subroutine is used to alter the sorting of the events database
# files so that we sort by day, then time.

sub date_sort {
	my ($aday, $atime) = (split(/\|/, $a))[0,1];
	my ($bday, $btime) = (split(/\|/, $b))[0,1];
	$aday <=> $bday || $atime cmp $btime;
}

# SUB TRIM_EVENTS #

# This subroutine will only be called once when the calendar is called for
# the very first time, if so configured.  It will delete all events that
# are older than a set number of months.

sub trim_events {
	my ($i, $te_month, $te_year, @event_files, $x, $y);
	my ($id);

# We set the te month and year to the current (localtime) month and year,
# and then subtract out the number of old months we want to keep, and format
# the whole into one number.  This provides us with a number that will be used
# to see if a .events file is to be deleted.

	$te_month = $ltmon;
	$te_year = $ltyear;
	$te_month -= $old_events;
	if ($te_month < 1) {
		$te_month += 12;
		$te_year--;
	}
	$y = "$te_year".sprintf("%.2d", $te_month);

# We now open up the directory that holds our .events files, and
# read through it, extracting all of the .events files and putting
# them into an array.

	opendir (DIR, $calendar_type);
	@event_files = grep { /\.events$/i } readdir (DIR);
	closedir (DIR);

# We now go through the array, extracting the year/month value of the
# file.  We then compare that value to our cut off year/month.  If the
# files number is less than our cutoff number, we open the file, read
# through it line by line, extracting all of the id numbers for any events
# in the month.  We then delete each of these event files, close the
# database file, and then delete the database file.  Note that we have
# to untaint the id numbers before we can use them to delete.

	foreach $i (@event_files) {
		$i =~ /(\d{6}\.events)$/io;
		$x = $1;
		if ($x < $y) {
			open (DATAFILE, "$calendar_type/$x") || &open_error("$x");
			while (<DATAFILE>) {
				chomp $_;
				$id = (split(/\|/,$_))[-1];
				$id =~ /(\d*)/o;
				$id = $1;
				if (-e "$path_to_events/$id") {
					unlink("$path_to_events/$id");
				}
			}
			close (DATAFILE);
			unlink("$calendar_type/$x");
		}
	}
}

# SUB GETFILELOCK #

# This subroutine gets a lock file so that a file can only be modified
# by one user at a time.  This is to prevent data mixing.  If you want
# to use flock, uncomment that line.  We only wait for 60 seconds if
# there is a lock file already in place, at which point we take over,
# assuming the old lock file is from a previous hang.

sub GetFileLock {
	my ($lock_file) = $_[0];
	my ($endtime) = 60;
	$endtime = time + $endtime;
	while (-e $lock_file && time < $endtime) {}
	open(LOCK_FILE, ">$lock_file");
#	flock(LOCK_FILE, 2);
}

# SUB RELEASEFILELOCK #

# This subroutine removes the passed lock file to free up a file
# for further editing.  If you want to use flock, uncomment that line.

sub ReleaseFileLock {
	my ($lock_file) = $_[0];
#	flock(LOCK_FILE, 8);
	close(LOCK_FILE);
	unlink($lock_file);
}

# SUB COUNTER #

# This subroutine provides us with a unique id nubmer for
# every event that is added to the calendar database.
 
sub counter {
	my($counter_file) = $_[0];
	my($item_number, $temp_item_number);

# We get a file lock on the counter file, so we don't mess the numbering
# up, then we open the file and get the current number out of it.

	&GetFileLock("$counter_lock");
	open (COUNTER_FILE, "$counter_file") || &open_error($counter_file);
	while (<COUNTER_FILE>) {
		$item_number = "$_";
	}
	close (COUNTER_FILE);

# We remove the new line character, then hold the number in a temporary
# id number.  We increment the original number by one, then open up
# the counter file, clobbering what was there before, and print the
# new item number to it with a new line, close the file, and remove
# the lock file.  We then return the original number.

	chomp ($item_number);
	$temp_item_number = $item_number;
	$item_number += 1;
	open (NOTE, ">$counter_file") || &open_error($counter_file);
	print NOTE "$item_number\n";
	close (NOTE);
	&ReleaseFileLock("$counter_lock");
	return ($temp_item_number);
}

# SUB OPEN_ERROR #

# If we have called this subroutine, it means that we have tried
# to open some file in the script, and failed.  We thus don't want
# to proceed, but we do want to provide the user with information
# on why we are not proceeding.

sub open_error {
	my ($filename) = $_[0];
	print qq!
</form><blockquote>I am sorry, but for some reason I was unable to open
<b>$filename</b>.  Would you please make sure that the filename is
correctly defined in the setup file, actually exists, and has the
right permissions relative to the web browser.  Thanks\!</blockquote>!;
	&footer;
	die;
}

# SUB JDATE #

# This subroutine was extracted from the standard date.pl file
# that comes with Perl, simply so we didn't have to require that
# file as well.

sub jdate {
	my($jd) = $_[0];
	my($jdate_tmp);
	my($m,$d,$y,$wkday);
	$wkday = ($jd + 1) % 7;
	$jdate_tmp = $jd - 1721119;
	$y = int((4 * $jdate_tmp - 1)/146097);
	$jdate_tmp = 4 * $jdate_tmp - 1 - 146097 * $y;
	$d = int($jdate_tmp/4);
	$jdate_tmp = int((4 * $d + 3)/1461);
	$d = 4 * $d + 3 - 1461 * $jdate_tmp;
	$d = int(($d + 4)/4);
	$m = int((5 * $d - 3)/153);
	$d = 5 * $d - 3 - 153 * $m;
	$d = int(($d + 5) / 5);
	$y = 100 * $y + $jdate_tmp;
	if($m < 10) { $m += 3; }
	else {	$m -= 9; ++$y; }
	return ($m, $d, $y, $wkday);
}

# SUB JDAY #

# This subroutine was extracted from the standard date.pl file
# that comes with Perl, simply so we didn't have to require that
# file as well.

sub jday {
	my($m,$d,$y) = @_;
	my($ya,$c);
	my ($brit_jd) = 2361222;
	if ($m > 2) { $m -= 3; }
	else { $m += 9; --$y; }
	$c = int($y/100);
	$ya = $y - (100 * $c);
	my ($jd) =  int((146097*$c)/4)+int((1461*$ya)/4)+int((153*$m+2)/5)+$d+1721119;
	warn("warning:  pre-dates British use of Gregorian calendar\n") if ($jd < $brit_jd);
	return ($jd);
}