#!/usr/bin/perl

########################################################################################
# Remark Web Survey Collection Script              Version 3.0            			   #
# (C) Copyright 2003     http://www.principiaproducts.com/info/copyrght.htm            #
# Principia Products, a Division of Gravic, Inc. http://www.principiaproducts.com/     #
########################################################################################
# COPYRIGHT NOTICE                                                           	       #
# (C) Copyright 2003 Principia Products, a Division of Gravic, Inc.            	       #
# All Rights Reserved.                  	 		 		       					   #
#										       										   #
# Warning: This program is protected by copyright laws and international               #
# treaties. Unauthorized reproduction or distribution of this program, or              #
# any poriton of it, may result in severe civil and criminal penalties and             #
# will be prosecuted to the maximum extent possible under the law.                     #
########################################################################################

########################################################################################
#             GLOBAL INCLUDE HEADER LIST					        				   #
########################################################################################	

#store server locations that will be used to build file names
($cgi_dir,$config_dir,$data_script) = &get_locations();

#add our cgi dir to the INC array
push (@INC,$cgi_dir);

#utility module used in RWS
require rwsutils3;

########################################################################################
#             GLOBAL CONSTANT LIST						       						   #
########################################################################################

#change these values to what you want to see in confirmation pages and email notifications for missing values
$MISSING_ANSWERS = "";
$MISSING_QUESTION_TEXT = "";
	
$CGI_MPD = "RWS_MPD";

#question suffix for Form Configuration file
$HTML_REPLACE_ERROR_TAG = "ERROR_MESSAGE";
$ERROR_NUM_FILE_ACCESS = "1000";
$ERROR_NUM_INVALID_PASSWORD = "2000";
$ERROR_NUM_PASSWORD_EXPIRED = "3000";

#my $cr = pack ('c',13);
#my $lf = pack ('c',10);
#$CRLF = $cr . $lf;

########################################################################################
#             GLOBAL STORAGE VARIABLES						       					   #
########################################################################################	

%form_configuration = ();
%form_directories = ();
%form_uid = ();
%hash_config_file = ();

$installation_config_file = &return_full_path($config_dir,'rwsad3.cfg');
$form_config_file = "";
$form_hash_file = "";
$session_uid = "";
$uid_file = "";

########################################################################################
#             MAIN PROCEDURES 							       						   #
########################################################################################	
   
&perform_form_action;

########################################################################################
# 			PERL SUBROUTINE / FUNCTION AREA				       						   #
########################################################################################

########################################################################################
# 	FUNCTION THAT APPENDS NEW HASHES TO AN EXISTING HASH			       			   #
#	USE: %new_hash = &append_hash (\%ORIGINAL_HASH,$KEY_NAME,\%APPEND_HASH);		   #	
########################################################################################
sub append_hash
{
	#local variable referencing passed in data - holds the original hash
	my %original_hash = %{$_[0]};
	
	#local variable referencing passed in data - holds the hash key name
	my $hash_key = $_[1];

	#local variable referencing passed in data - holds the append hash
	my %new_hash = %{$_[2]};
	
	#local variables for indexing
	my $key_index = "";	
	my $new_key = "";

	#remove old hash before storing new values
	delete $original_hash{$hash_key};

	#loop thru the keys in the appending hash
	foreach $new_key (keys %new_hash)
	{
		#ignore values that do not matter (hidden vars, etc)
		if(($new_key ne 'FORM_ACTION') && ($new_key ne 'BACK') && ($new_key ne 'PAUSE') && ($new_key ne 'RWS_NAME') && ($new_key ne 'PAGE_KEY') && ($new_key !~ /_RWS_TYPE/) && ($new_key !~ /_RWS_NAME/) && ($new_key !~ /_RWS_NA/) && ($new_key ne 'x') && ($new_key ne 'y'))
		{
			#replace crlf with a bell
			$new_hash{$new_key} =~ s/\r\n/\a/g;

			#append new hash to existing hash at designated family/key
			$original_hash{$hash_key}{$new_key} = $new_hash{$new_key};
		}
	}	
	#the hash has been added, so we may exit returning the new hash
	return (%original_hash);
}

########################################################################################
# 	FUNCTION THAT MERGES THE UID HASH WITH AN EXISTING HASH			       			   #
#	USE: %new_hash = &merge_uid_hash (\%ORIGINAL_HASH,$SKIP_KEY_NAME,);		       	   #	
########################################################################################
sub merge_uid_hash
{
	#local variable referencing passed in data - holds the original hash
	my %original_hash = %{$_[0]};
	
	#local variable referencing passed in data - holds the hash key name
	my $skip_hash_key = $_[1];
	
	#local variables for indexing
	my $key_index = "";	
	my $uid_key = "";
	my $tmp_index = "";
	my $tmp_key = "";

	#loop thru the keys in the uid hash
	foreach $uid_key (keys %form_uid)
	{
		#skip the requested key as well as the MISC heading - also skip x + y (image buttons)		
		next if (($uid_key eq $skip_hash_key) || ($uid_key eq '[MISC]') || ($uid_key eq 'x') || ($uid_key eq 'y'));

		#loop thru the keys for the specific header key
		foreach $key_index (sort keys %{$form_uid{$uid_key}})
		{	
			next if(($key_index eq 'QUESTION_START') || ($key_index eq 'QUESTION_END') || ($key_index !~ /^Q/));

			#turns '[Page_X]' into X]
			$tmp_index = (split(/\_/,$uid_key))[1];

			#turns 'X]' into X
			$tmp_index = (split(/\]/,$tmp_index))[0];

			#do NOT write out info for pages that were NOT truly submitted (BACK BUTTON WAS USED)
			@visited_pages = split(/\,/,$form_uid{'[MISC]'}{'SubmittedPages'});
			foreach $tmp_key (@visited_pages)
			{
				if($tmp_key eq $tmp_index)
				{
					$original_hash{$key_index} = $form_uid{$uid_key}{$key_index};
					last;
				}
			} 
		}
	}

	#the hash has been added, so we may exit returning the new hash
	return (%original_hash);
}

########################################################################################
# 	FUNCTION THAT LOADS A SUB-HASH FROM A HASH OF HASHES			       			   #
#	USE: %RETURN_HASH = &load_hash (\%ORIGINAL_HASH,$KEY_NAME);		       			   #	
########################################################################################
sub load_hash
{
	#local variables referencing passed in data
	my %original_hash = %{$_[0]};
	
	#local variable referencing passed in data - holds the hash key name
	my $hash_key = $_[1];

	#local variables for indexing
	my $key_index;
	
	#initialize our return hash
	my %ret_hash = ();

	#loop thru the existing hash searching for the passed in key
	foreach $key_index (keys %original_hash)
	{
		#if the key passed in matches the current family then continue
		if ($hash_key eq $key_index)
		{
			#set the return hash to the hash at the designated family/key
			$ret_hash{$key_index} = $original_hash{$key_index};	

			#the hash has been loaded, so we may exit returning the new hash
			return (%ret_hash);
		}
	}
	#return the original hash with no additions as key was not found
	return (%ret_hash);
}

########################################################################################
# 	FUNCTION THAT RELOADS AN HTML PAGE WITH STORED VALUES VIA REGULAR EXPRESSIONS  	   #
#	USE: $NEW_HTML = &reload_form_replacement($HTML_FILE,$ERR_TXT,$ERR_NUM,$PAGE_KEY); #	
########################################################################################
sub reload_form_replacement
{
	#store the passed in file names
	my $html_file = $_[0];
	my $err_text = $_[1];
	my $err_num = $_[2];
	my $target_key = $_[3];
	my $all_lines = "";
	my $key = "";
	my $sub_key = "";
	my $base_key = "";
	my $whole_error_tag = "";	
	my $source_lines = "";
	my @multi_list = ();	
	my %key_values = ();
	my $start_err = "";
	my $end_err = "";
	my $border = '0';
	my $confirm_data = "";
	my $back_location = "";
	my @file_data = ();
	my $confirm_text = "";
	my $begin_confirm_copy = 0;

	#check to see if the source file exists
	if (-e $html_file)
	{
		#open the source file and set the source file handle
		open (SRC_FILE, $html_file) || die &show_server_error($ERROR_NUM_FILE_ACCESS,"File Access Error",$form_configuration{'[MISC]'}{'FileAccessError'} . " [" . $html_file . "]", __LINE__);
	}
	else
	{
		&general_error_screen('File Error', '<B>Module:</B> RWS3<BR><B>Line:</B> ' . __LINE__ . '<BR><B>Details:</B> <I>' . $html_file . '</I> does not exist on the system',$form_configuration{'[MISC]'}{'AdminAddress'});
		exit;
	}

	#read in the uid file
	if (-e $uid_file)
	{
		%form_uid = &read_config($uid_file,1);
	}

	#add the current page to the uid file
	$form_uid{'[MISC]'}{'ActiveKey'} = $target_key;
	 
	#write out a uid file
	&write_config(\%form_uid,$uid_file,1);

   	#read the file into an array 
	@file_data=<SRC_FILE>;

	#close the source file because we are finished reading in the key=value pairs
	close (SRC_FILE);

	#loop thru storing the lines
 	foreach $source_lines (@file_data)
 	{	
 		#remove the \n character
 		chop ($source_lines);

		#if we are copying the html section for the confirm page
		if($begin_confirm_copy == 1)
		{
			#make sure we have not reached the end of the copy
			if($source_lines =~ "@*(CONFIRM_END)")
			{
				$begin_confirm_copy=0;
			}
			else
			{
				#copy the html into a scalar
				$confirm_text .= $source_lines;
			}
		}
		#set the copy hmtl flag and insert a replacement holder
		elsif($source_lines =~ "@*(CONFIRM_START)")
		{
			
			$begin_confirm_copy = 1;
			$all_lines .= "@*(CONFIRM_REPLACE)\n";
		}
		#copy the regular html
		else
		{
			$all_lines .=  $source_lines;
		} 		
 	}

	#handle possible error case by inserting message OR removing error TAG
	if($err_text ne '')
	{
		$border = $form_configuration{'[MISC]'}{'ErrorBorder'};
		$whole_error_tag = '<TABLE WIDTH="100%" BORDER="' . $border . '" CELLPADDING="6" CELLSPACING="3" BGCOLOR="' . $form_configuration{'[MISC]'}{'ErrorBackColor'} . '"><TR><TD>';

		if($form_configuration{'[MISC]'}{'ErrorFontBold'} eq '1')
		{
			$whole_error_tag .= '<B>';
		}
		if($form_configuration{'[MISC]'}{'ErrorFontItalic'} eq '1')
		{
			$whole_error_tag .= '<I>';
		}
		if($form_configuration{'[MISC]'}{'ErrorFontUnderline'} eq '1')
		{
			$whole_error_tag .= '<U>';
		}
		
		#construct main error tag here
		$whole_error_tag .= '<FONT FACE="' . $form_configuration{'[MISC]'}{'ErrorFontName'} . '" SIZE="' . $form_configuration{'[MISC]'}{'ErrorFontSize'} . '" COLOR="' . $form_configuration{'[MISC]'}{'ErrorFontColor'} . '">' . $err_text . '</FONT>';
		
		if($form_configuration{'[MISC]'}{'ErrorFontUnderline'} eq '1')
		{
			$whole_error_tag .= '</U>';
		}
		if($form_configuration{'[MISC]'}{'ErrorFontItalic'} eq '1')
		{
			$whole_error_tag .= '</I>';
		}
		if($form_configuration{'[MISC]'}{'ErrorFontBold'} eq '1')
		{
			$whole_error_tag .= '</B>';
		}
		
		$whole_error_tag .= '</TD></TR></TABLE>';

		#construct error replacement tags
		$start_err = 'Q' . $err_num . '_START_ERR';
		$end_err = 'Q' . $err_num . '_END_ERR';

		$all_lines =~ s/\*\($HTML_REPLACE_ERROR_TAG\)/$whole_error_tag/g;
		$all_lines =~ s/\@\*\($start_err\)/<FONT COLOR="$form_configuration{'[MISC]'}{'ErrorFontColor'}">*/g;	
		$all_lines =~ s/\@\*\($end_err\)/<\/FONT>/g;
	}
	else
	{
		$all_lines =~ s/\*\($HTML_REPLACE_ERROR_TAG\)//g;
	}

	#insert confirmation page data
	if($confirm_text ne '')
	{
		$confirm_data = &add_confirmation_data($confirm_text,0,1);
		$all_lines =~ s/\@\*\(CONFIRM_REPLACE\)/$confirm_data/g;
	}

	#replace remaining error tags
	$all_lines =~ s/\@\*\(Q[^_END_ERR]*_START_ERR\)//g;	
	$all_lines =~ s/\@\*\(Q[^_START_ERR]*_END_ERR\)//g;

	#read in the key=value pairs that must be merged back into the HTML file
	%key_values = &read_config($uid_file,1);
	
	#use the form config file to search for defaults
	if(!(exists $key_values{$target_key}))
	{
		%key_values = %form_configuration;
	}	

	#loop thru the key values replacing the special characters in the HTML file with the saved values
	foreach $key (keys %{$key_values{$target_key}})
	{					  
		#reinsert lf
		$key_values{$target_key}{$key} =~ s/\a/\n/g;
		
		#this will handle checkboxes '@^()'
		$all_lines =~ s/\@\^\(\Q$key\E\)/CHECKED/g;

		#this will handle radio buttons '@+()'
		$all_lines =~ s/\@\+\(\Q$key$key_values{$target_key}{$key}\E\)/CHECKED/g;

		#make sure there exists an '%' sign if there is than we have a multi-list
		if ($key =~ /MPD/)
		{	
			@multi_list = split(/\-/, $key);
			
			#this will handle mulitple lists '@!()' by removing the incrementing number (index)
			$all_lines =~ s/\@\!\(\Q$multi_list[0]$key_values{$target_key}{$key}\E\)/SELECTED/g;
		}
		else
		{
			#this will handle single lists '@!()'
			$all_lines =~ s/\@\!\(\Q$key$key_values{$target_key}{$key}\E\)/SELECTED/g;
		}
	
		#escape bad characters:  *TO UN-ESCAPE USE THE FOLLOWING - [$variable] =~ s/&#(\d+);/pack("c",$1)/ge;
		$key_values{$target_key}{$key} =~ s/([^\w\s])/'&#'.ord($1).';'/ge;

		#this will handle text boxes and textareas '@*()'
		$all_lines =~ s/\@\*\(\Q$key\E\)/$key_values{$target_key}{$key}/g;
	}
	
	#insert the uid into our form '@*()'
	if(exists $form_configuration{'[MISC]'}{'FormName'})
	{
		$all_lines =~ s/\@\*\(form_query\)/\?FORM\=$form_configuration{'[MISC]'}{'FormName'}/g;
	}
	else
	{
		$all_lines =~ s/\@\*\(form_query\)//g;
	}

	#insert the uid into our form '@*()'
	if($session_uid ne '')
	{
		$all_lines =~ s/\@\*\(uid\)/\&UID\=$session_uid/g;
	}
	else
	{
		$all_lines =~ s/\@\*\(uid\)//g;
	}
	
	#insert the image server script into form '@*()'
	$all_lines =~ s/\@\*\(img\)/$form_directories{'[Defaults]'}{'ImageScript'}/g;  
	
	#insert the data script into form '@*()'
	$all_lines =~ s/\@\*\(data\)/$data_script_location/g;

	#replace remaining textboxes with nothing (removes special characters)	
	$all_lines =~ s/\@\*\(.*?\)//g;

	#replace remaining checkboxes with nothing (removes special characters)	
   	$all_lines =~ s/\@\^\(.*?\)//g;

	#replace remaining radio buttons with nothing (removes special characters)	
	$all_lines =~ s/\@\+\(.*?\)//g;

	#replace remaining lists with nothing (removes special characters)	
	$all_lines =~ s/\@\!\(.*?\)//g;

	#return the 'new' source file with the values merged into the HTML file
	return $all_lines; 
}

########################################################################################
# 	FUNCTION THAT WRITES OUT ALL OF THE HASH VALUES to STDOUT 		       			   #
#	USE: &print_hash(%HASH_NAME);		       				       					   #		
########################################################################################
sub print_hash
{
	#variables holding parameter data
	my %hash_array = @_;

	#local variables
	my $hash_family = "";
	my $hash_key = "";
	
	#loop thru printing all hash values
	foreach $hash_family (keys %hash_array)
	{
		print "\n$hash_family\n";
		foreach $hash_key (keys %{$hash_array{$hash_family}})
		{
 			print "$hash_key: $hash_array{$hash_family}{$hash_key}\n";
		}
	}
}

########################################################################################
# 	FUNCTION THAT VALIDATES CREDENTIALS FROM A UID FILE     		       			   #	
#	USE: &validate_credentials($HASH);	               								   #		
########################################################################################
sub validate_credentials
{
	my $respondent_hash = $_[0];
	my %file_hash = ();
	my $key = "";

	if(!(-e $form_hash_file))
	{	
		return (0);
	}
	else
	{
		#read the hash file - should have headers
		%file_hash = &read_config($form_hash_file,0);
		
		#loop thru each key=value pair looking for the 'ID' key
		foreach $key (keys %file_hash)
		{
			if ($key eq $respondent_hash)
			{
				#if we are trying to RELOGIN - make sure passwords match
				if($form_uid{'[MISC]'}{'ID'} ne '')
				{
					if ($key eq $form_uid{'[MISC]'}{'ID'})
					{
						return (1);
					}
					else
					{
						return (-1);
					}	
				}
				else
				{
					return (1);
				}
				last;
			}
		}
	}
	return (0);	
}

########################################################################################
# 	FUNCTION THAT INCREMENTS PASSWORD USES			     		       				   #	
#	USE: $valid_password = &password_status($PASSWORD_FILE,$PASSWORD_HASH,$INC);       #		
########################################################################################
sub password_status
{
	my $file_name = $_[0];
	my $password_hash = $_[1];
	my $increment_password = $_[2];
	my %file_hash = ();
	my $key = "";
	my $lock_file = "";
	my $lock_cnt = 0;

	#determine if there was a password limit established
 	if($form_configuration{'[MISC]'}{'PasswordUses'} ne '0')
	{
		#generate a lock file name		
		$lock_file = $file_name . '.lck';
	
		#read the config file that was passed in - should have headers
		%file_hash = &read_config($file_name,0);

		#if above the allowed amount
		if($hash_config_file{$password_hash} >= $form_configuration{'[MISC]'}{'PasswordUses'})
		{
			&show_server_error($ERROR_NUM_PASSWORD_EXPIRED,"Password Expired",$form_configuration{'[MISC]'}{'PasswordExpiredError'}, __LINE__);
			&add_log_record('password expired','denied');
			return 0;
		}
		elsif($increment_password == 1)
		{   				
			#if lock file exists, delay up to 5 seconds before opening the password file
			while ((-e $lock_file) and ($lock_cnt < 5)) 
			{
				sleep 1;
				$lock_cnt++;
			}

			#if the lock file does not exist, create it
			if (!(-e $lock_file))
			{
				if (open (LOCK_FILE, ">$lock_file")) 
				{
					close(LOCK_FILE);
				}
			}	   
			
			#increment the value
			$file_hash{$password_hash}++;	

			#write back out the password file with the adjusted increment
			&write_config (\%file_hash,$file_name,0);
			
			#clean up the lock file if it exists
			if(-e $lock_file)
			{
				unlink $lock_file; 
			}

			#return ok if increment successful
			return 1;
		}
		else
		{
			#clean up the lock file if it exists
			if(-e $lock_file)
			{
				unlink $lock_file; 
			}

			#return ok if not incrementing and not expired
			return 1;
		}
	}
	else
	{
		#clean up the lock file if it exists
		if(-e $lock_file)
		{
			unlink $lock_file; 
		}

		#return ok if there is no limit on password uses
		return 1;
	}
}

########################################################################################
# 	FUNCTION THAT HANDLES BRANCHING				     		       					   #	
#	USE: $next_page = &perform_branch($PAGE_HEADER_KEY, %SUBMITTED_DATA);		       #		
########################################################################################
sub perform_branch
{
	my $hash_key = $_[0];
	my %submit_hash = %{$_[1]};
	my %page_rules = ();
	my %target_hash = ();
	my $target_page_key ="";
	my $target_page ="";	
	my $key = "";
	my $value = "";
	my $tmp_page = "";

	#add the previously submitted pages from the uid file
	%submit_hash = &merge_uid_hash(\%submit_hash,$hash_key);

	#extract the page of the form config hash 
	%page_rules = &load_hash (\%form_configuration,$hash_key);

	#loop thru all the keys evaluating rules
	foreach $key (sort keys %{$page_rules{$hash_key}})
	{
		#if we have located a page rule
		if(substr($key,0,5) eq "#RULE")
		{
			#get the rule and the target page key (delimited by tab)
			($value, $target_page_key) = split (/\t/, $page_rules{$hash_key}{$key});

			#check for the [Auto] setting
			if($target_page_key eq '[Auto]')
			{
				if($hash_key ne '[confirmation_page]')
				{
					#turns '[Page_X]' into X]
					$hash_key = (split(/\_/,$hash_key))[1];

					#turns 'X]' into X
					$hash_key = (split(/\]/,$hash_key))[0];

					#increment the page
					$hash_key++;

					#assign target to what 'should be the next page'
					$target_page_key = '[page_' . $hash_key . ']'; 
				}
				else
				{
					#try to locate a complete form page in the sequence
					$target_page_key = '[complete_page_' . $hash_key . ']';
					if(!(exists $form_configuration{$target_page_key}))	
					{
						if($form_configuration{'[MISC]'}{'FirstCompletePage'} =~ /^http/)
						{
							#make sure the password has not expired
							if(&password_status($form_hash_file,$form_uid{'[MISC]'}{'ID'},0) == 0)
							{
								exit;
							}
							&browser_redirect($form_configuration{'[MISC]'}{'FirstCompletePage'},$form_directories{'[Defaults]'}{'CGIRedirect'},\%submit_hash);
							
							#be sure to return 'complete_page' so we know we are finished
							return ("complete_page_x");
						}
						else
						{
							$target_page_key = '[complete_page_' . $form_configuration{'[MISC]'}{'FirstCompletePage'} . ']';
							if(!(exists $form_configuration{$target_page_key}))	
							{
	 	   						&general_error_screen('Form Branch Error','<B>Module:</B> RWS3<BR><B>Line:</B> ' . __LINE__ . '<BR><B>Details:</B>  The designated branch path is invalid. Please contact the form administrator before continuing.',$form_configuration{'[MISC]'}{'AdminAddress'});
							}
						}
					}
				}

		  		#if there are no more pages in the sequence, load the 1st success page 
				if(!(exists $form_configuration{$target_page_key}))	
				{
					#try to locate a confirmation page in the sequence else, try complete page
					$target_page_key = '[confirmation_page]';
					if(!(exists $form_configuration{$target_page_key}))	
					{
						#try to locate a complete form page in the sequence
						$target_page_key = '[complete_page_' . $hash_key . ']';
						if(!(exists $form_configuration{$target_page_key}))	
						{
							if($form_configuration{'[MISC]'}{'FirstCompletePage'} =~ /^http/)
							{
								#make sure the password has not expired
								if(&password_status($form_hash_file,$form_uid{'[MISC]'}{'ID'},0) == 0)
								{
									exit;
								}
								&browser_redirect($form_configuration{'[MISC]'}{'FirstCompletePage'},$form_directories{'[Defaults]'}{'CGIRedirect'},\%submit_hash);
								
								#be sure to return 'complete_page' so we know we are finished
								return ("complete_page_x");
							}
							else
							{
								$target_page_key = '[complete_page_' . $form_configuration{'[MISC]'}{'FirstCompletePage'} . ']';
								if(!(exists $form_configuration{$target_page_key}))	
								{
		 	   						&general_error_screen('Form Branch Error','<B>Module:</B> RWS3<BR><B>Line:</B> ' . __LINE__ . '<BR><B>Details:</B>  The designated branch path is invalid. Please contact the form administrator before continuing.',$form_configuration{'[MISC]'}{'AdminAddress'});
								}
							}
						}
					}
				}
			}
			
			#if we are to branch to a random page, simply set the target key = the page just submitted
			elsif($target_page_key eq '[Random]')
			{
				$target_page_key = $hash_key;
			}

			#determine if the branching criteria for this rule was met OR failsafe page
			if ($value eq "*default*")
			{		
				#extract the page from the form config hash 
				%target_hash = &load_hash (\%form_configuration,$target_page_key);	
				
				#determine if the page we are supposed to go to is part of a random group
				if (defined $target_hash{$target_page_key}{"#RANDOM_ID#"})
				{
					#if greater than 0 then we have a random group
					if($target_hash{$target_page_key}{"#RANDOM_ID#"} ne '-1')
					{
						#get the key from the next random page
						$target_page_key = 	&next_random_page($target_hash{$target_page_key}{"#RANDOM_ID#"});

						#if a URL was specified goto that page instead
						if($target_page_key =~ /^http/)
						{
							#make sure the password has not expired
							if(&password_status($form_hash_file,$form_uid{'[MISC]'}{'ID'},0) == 0)
							{
								exit;
							}
							&browser_redirect($target_page_key,$form_directories{'[Defaults]'}{'CGIRedirect'},\%submit_hash);
							return ($target_page_key);  
						}
						else
						{
							#extract the new random page from the form config hash 
							%target_hash = &load_hash(\%form_configuration,$target_page_key);
						}
					}
				}
		
				#get the target file from the target hash
				$target_page = $target_hash{$target_page_key}{"#SRC#"};
	
				#if a URL was specified goto that page instead
				if($target_page =~ /^http/)
				{
					#make sure the password has not expired
					if(&password_status($form_hash_file,$form_uid{'[MISC]'}{'ID'},0) == 0)
					{
						exit;
					}
					&browser_redirect($target_page,$form_directories{'[Defaults]'}{'CGIRedirect'},\%submit_hash); 
				}
				else
				{
					#concatenate the form's directory with the target page
					$target_page = &return_full_path($form_directories{'[Forms]'}{$form_configuration{'[MISC]'}{'FormName'}},$target_page);	

					#make sure the password has not expired
					if($target_page =~ /complete\_page/)
					{
						if(&password_status($form_hash_file,$form_uid{'[MISC]'}{'ID'},0) == 0)
						{
							exit;
						}
					}

					#navigate to the appropriate page
					&display_html(&reload_form_replacement($target_page,'','',$target_page_key));
				}	
				#return success
				return ($target_page_key);
				
				last;
			}
			elsif (eval($value))
			{
				#extract the page from the form config hash 
				%target_hash = &load_hash(\%form_configuration,$target_page_key);	
				
				#determine if the page we are supposed to go to is part of a random group
				if (defined $target_hash{$target_page_key}{"#RANDOM_ID#"})
				{
					if($target_hash{$target_page_key}{"#RANDOM_ID#"} ne '-1')
					{
						#get the key from the next random page
						$target_page_key = 	&next_random_page($target_hash{$target_page_key}{"#RANDOM_ID#"});

						#if a URL was specified goto that page instead
						if($target_page_key =~ /^http/)
						{
							if(&password_status($form_hash_file,$form_uid{'[MISC]'}{'ID'},0) == 0)
							{
								exit;
							}
							&browser_redirect($target_page_key,$form_directories{'[Defaults]'}{'CGIRedirect'},\%submit_hash);
							return ($target_page_key);  
						}
						else
						{
							#extract the new random page from the form config hash 
							%target_hash = &load_hash(\%form_configuration,$target_page_key);
						}
					}
				}

				#get the target file from the target hash
				$target_page = $target_hash{$target_page_key}{"#SRC#"};

				#if a URL was specified goto that page instead
				if($target_page =~ /^http/)
				{
					if(&password_status($form_hash_file,$form_uid{'[MISC]'}{'ID'},0) == 0)
					{
						exit;
					}
					&browser_redirect($target_page,$form_directories{'[Defaults]'}{'CGIRedirect'},\%submit_hash);  
				}
				else
				{
					#concatenate the form's dircetory with the target page
					$target_page = &return_full_path($form_directories{'[Forms]'}{$form_configuration{'[MISC]'}{'FormName'}},$target_page);	
					
					if($target_page =~ /complete\_page/)
					{
						if(&password_status($form_hash_file,$form_uid{'[MISC]'}{'ID'},0) == 0)
						{
							exit;
						}
					}

					#navigate to the appropriate page
					&display_html(&reload_form_replacement($target_page,'','',$target_page_key));
				}	
				#return success
				return ($target_page_key);	
				
				last;
			}
		}
	}

	#return failure
	return (0);
}
########################################################################################
# 	FUNCTION THAT GETS CGI + CONFIG DIRECTORIES  	       			       			   #	
#	USE: @dirs = &get_locations();	 	       										   #		
########################################################################################
sub get_locations
{
	my $dir_config = "";
	my $script_name = "";
	my $cgi_dir = "";
	my $config_dir = "";	
	my @dirs = ();
	
	#if running on Dos/Windows
	if (index($0,'\\') != -1)
	{
		$script_name = substr($0, rindex($0, '\\') + 1);
		$cgi_dir = substr($0, 0, -(length($0) - rindex($0, '\\') - 1));
	}
	#running on *nix
	else 
	{
		$script_name = substr($0, rindex($0, '/') + 1); 
		$cgi_dir = substr($0, 0, -(length($0) - rindex($0, '/') - 1));
	}

	$config_dir = $cgi_dir;
	$dir_config = $cgi_dir . 'rwsdir3.cfg';

	#check if user specfied different directory for config files
	if (-e $dir_config) 
	{
		if (open (DIR_FILE, $dir_config))
		{
			$config_dir = <DIR_FILE>;
			chomp($config_dir);
			if (!-d $config_dir)
			{
				$config_dir = $cgi_dir;
			}
			close (DIR_FILE);
		}
	}

	#check to see if there is a trailing slash
	if ($config_dir !~ m#[/|\\]$#)
	{
		#if not, find the first slash and append it to the end of the directory
		if ($config_dir =~  m#.*?([/|\\])#)
		{
			$config_dir .= $1;
		}
	}

	#add the directories to the array hash
	push (@dirs,$cgi_dir,$config_dir,$script_name);

	return (@dirs);
}

########################################################################################
# 	FUNCTION THAT GRABS FORM NAME FROM THE QUERY STRING 		       				   #	
#	USE: $form_name = &get_form_name();		       	       							   #		
########################################################################################
sub get_form_name
{
	my $query_string = "";
	my $form = "";
		
	#get the query string	
	$query_string = $ENV{'QUERY_STRING'};
	if($query_string eq '')
	{
		&general_error_screen('Form Not Specified','<B>Module:</B> RWS3<BR><B>Line:</B> ' . __LINE__ . '<BR><B>Details:</B> A form name must be appended to the end of the data script URL.<BR><DIR><I>Example:</I> ' . $ENV{'SCRIPT_NAME'} . '?FORM=FormNameHere</DIR>');
		exit;
	}
	else
	{
		$form = &get_query_parameter('FORM');
	}	 
	return lc($form);
}
########################################################################################
# 	FUNCTION PERFORMS THE ACTION OF THE FORM 		       		       				   #	
#	USE: &perform_form_action();					       	       					   #		
########################################################################################
sub perform_form_action
{
	my %submitted_data = ();
	my $form_name = ""; 
	my $key = "";
	my $action = "";
	my $method = "";
	my $tmp_hash = "";
	my $next_page = "";
	my $back_location = "";
	my $timed_out = '1';
	my $full_url = "";
	my $current_page = "";
	my $archive_file = "";
	my $id_param = "";
	my $tmp_page = "";
	my $target_page = "";
	my $address = "";
	my @emails = ();
	my $valid_pass = 0;
	my $email_body = "";
	my %merged_data = ();
	my $lock_cnt = 0;
	my $uid_lock_file = "";
	my @pages = ();
	my $last_page = "";
	my $active_page = "";

	#get the form the script is requesting
	$form_name = &get_form_name;
	
	#if missing or not found then show message and exit
	if($form_name eq '')
	{
		&general_error_screen('Form Not Specified','<B>Module:</B> RWS3<BR><B>Line:</B> ' . __LINE__ . '<BR><B>Details:</B> A form name must be appended to the end of the data script URL.<BR><DIR><I>Example:</I> ' . $ENV{'SCRIPT_NAME'} . '?FORM=FormNameHere</DIR>');
		exit;
	}

	#read the installation configuration file into the global hash
	%form_directories = &read_config($installation_config_file,1);

	#set the form config location correctly based on the form name
	$form_config_file = &return_full_path($form_directories{'[Forms]'}{$form_name},$form_name . '.cfg');

	#set the hashlist config location correctly based on the form name
	$form_hash_file = &return_full_path($form_directories{'[Forms]'}{$form_name},'hash.pwd');

	#read the hash file of passwords in
	if(-e $form_hash_file)
	{
		%hash_config_file = &read_config($form_hash_file,0);
	}

	#make sure that the form was installed before continuing
	if(!(exists $form_directories{'[Forms]'}{$form_name}))
	{ 
		&general_error_screen('Form Not Found','<B>Module:</B> RWS3<BR><B>Line:</B> ' . __LINE__ . '<BR><B>Details:</B> The <B>' . $form_name . '</B> Form could not be located. Please try reinstalling your form before continuing.');
		exit;
	}
	
	#read the form configuration into the global hash
	%form_configuration = &read_config($form_config_file,1);

	#get the data script location from the config file
	$data_script_location = $form_configuration{'[MISC]'}{'DataScript'};
		
	#if a GET then display the login screen	or reload the old location
	if($ENV{'REQUEST_METHOD'} eq 'GET')
	{
		#get the UID from the query string	
		$session_uid = &get_query_parameter('UID');

		#if the UID variable is defined
		if($session_uid ne '')
		{
			#reconstruct the uid file name
			$uid_file = &return_full_path($form_directories{'[Forms]'}{$form_name},$session_uid);
			$uid_file .= '.uid';

			#if the UID file does NOT exist, then treat as new session
			if(!(-e $uid_file))
			{
				$session_uid = '';	
			}
		}

		#if UID is blank then we are on a new session
		if($session_uid eq '')
		{
			#generate a session_id that will be passed in the QUERY_string
			$session_uid = &generate_uid();
		
			#if password protected, display login screen
			if($form_configuration{'[MISC]'}{'PasswordRequired'} eq '1')
			{
				#attempt to read in the ID parameter from the query string
				$id_param = &get_query_parameter('ID');
				
				#if they are NOT auto-logging in from a link
				if($id_param eq '')
				{
					#create the initial uid file
					&generate_uid_file;

					#write out a uid file
					&write_config(\%form_uid,$uid_file,1);

					#construct the location of the login page
					$back_location = &return_full_path($form_directories{'[Forms]'}{$form_name},'login_page.html');

					#display the user constructed login page else display basic login page
					if (-e $back_location)
					{
						&display_html(&reload_form_replacement($back_location,'','','[login_page]'));					
					}
					else
					{
						&display_login_page;
					}
					exit;
				}
			}
			
			#not password protected
			else
			{
				#create the initial uid file
				&generate_uid_file;

				#write out a uid file
				&write_config(\%form_uid,$uid_file,1);

				#read in the uid file
				%form_uid = &read_config($uid_file,1);
				
				#load the correct first page
				&load_first_page();
			}
		}

		#reloading a pre-existing form
		else
		{	 
			#if password protected, diplay login screen
			if($form_configuration{'[MISC]'}{'PasswordRequired'} eq '1')
			{		   
				#construct the location of our last page
				$back_location = &return_full_path($form_directories{'[Forms]'}{$form_name},'login_page.html');

				#display the user constructed login page else display basic login page
				if (-e $back_location)
				{
					&display_html(&reload_form_replacement($back_location,'','','[login_page]'));					
				}
				else
				{
					&display_login_page;
				}
				exit;
			}
			else
			{
				#read in the uid file
				%form_uid = &read_config($uid_file,1);

				#determine which page should be loaded - should be the page they paused on
				$next_page = &last_submitted_page;

				#if a page value was returned
				if ($next_page ne '0')
				{
					#get the expected file location
					$back_location = &return_full_path($form_directories{'[Forms]'}{$form_name},'page_' . $next_page . '.html');
	  				
	  				#display the user constructed page
	  				&display_html(&reload_form_replacement($back_location,'','','[page_' . $next_page . ']'));
		  			
		  			exit;
				}
				#page boundary error occured so display the first page in the form
				else
				{
					&load_first_page();
				}
			}
		}	
	}

	#store the submitted data in the global hash
	%submitted_data = &store_post_data();

	#store the session UID that is being past as part of the consstructed query string
   	if($session_uid eq "")
   	{
   		$session_uid = &get_query_parameter('UID');
   	}	 	 

	#reconstruct the uid file base name
	$uid_file = &return_full_path($form_directories{'[Forms]'}{$form_name},$session_uid);
	
	#reconstruct the uid lock file name
	$uid_lock_file = $uid_file . '.lck';
	
	#reconstruct the uid file name
	$uid_file .= '.uid';
	
	#if lock file exists, delay up to 10 seconds before opening the data file
	while ((-e $uid_lock_file) and ($lock_cnt < 10)) 
	{
		sleep 1;
		$lock_cnt++;
	}

	#if the uid file exists read it into global hash
	if(-e $uid_file)
	{
		%form_uid = &read_config($uid_file,1);
	}
   	
	#if the uid file does not exist and we are not loading from a link report to the user that the session has expired
   	elsif($id_param eq '')
	{
 		&general_error_screen("Session Expired","<B>Module:</B> RWS3<BR><B>Line:</B> " . __LINE__ . "<BR><B>Details:</B> The current session has expired due to a form submittal.",$form_configuration{'[MISC]'}{'AdminAddress'});	
 		exit; 
   	}

	#avoid multiple submit collisions
	if (defined $submitted_data{'PAGE_KEY'})
	{
		#if the current page does NOT equal the page we are trying to submit from
		if($form_uid{'[MISC]'}{'ActiveKey'} ne $submitted_data{'PAGE_KEY'})
		{
			#split the submitted pages string into hash
			@pages = split (/\,/, $form_uid{'[MISC]'}{'SubmittedPages'});

			#get the previous page in the sequence
			$last_page = $pages[$#pages];

			#turns '[Page_X]' into X]
			$active_page = (split(/\_/,$form_uid{'[MISC]'}{'ActiveKey'}))[1];

			#turns 'X]' into X
			$active_page = (split(/\]/,$active_page))[0];

			#push the active page back onto the queue IF IT IS NOT ALREADY THE LAST ITEM
			if($last_page ne $active_page)
			{
				&add_to_submitted_pages($form_uid{'[MISC]'}{'ActiveKey'});
			}
			
			#report the sequence error to the user 
			&general_error_screen("Invalid Page Sequence","<B>Details:</B> This page was submitted out of sequence; this may be a result of using the browser's navigation buttons.<BR>Click the continue button below to return to the last submitted page.",$form_configuration{'[MISC]'}{'AdminAddress'},1,$data_script_location,,"Continue",1);	
	 		exit;
		} 
	}

	#if attempting an auto form login	
	if($id_param ne '')
	{
		#used for password protected surveys only
		require rwsmd5;

		#hash the password passed in
		$tmp_hash = &HexDigest($id_param);
		
		#attempt validation sending in the password hash	  
		$valid_pass = &validate_credentials($tmp_hash);

		#if the password is valid
		if ($valid_pass == 1)
		{			  
			#make sure the password has not expired
			if(&password_status($form_hash_file,$tmp_hash,0) == 0)
			{
				exit;
			}
			
			#generate a UID file
			&generate_uid_file();

			#update last access time
			$form_uid{'[MISC]'}{'LastAccessTime'} = time;
			
			#update the uid file with the password hash used to gain access
			$form_uid{'[MISC]'}{'ID'} = $tmp_hash;

			#write out the uid file
			&write_config(\%form_uid,$uid_file,1);
			
			#get the next page, determine if there were already submissions
			$next_page = &last_submitted_page($submitted_data{'PAGE_KEY'});
			
			if ($next_page ne '0')
			{
				#get the expected file location	of the last submitted page
				$back_location = &return_full_path($form_directories{'[Forms]'}{$form_name},'page_' . $next_page . '.html');	
				
				#add a record to the log file				
				&add_log_record('auto form access','permitted');

				#display the constructed html page
				&display_html(&reload_form_replacement($back_location,'','','[page_' . $next_page . ']'));

				exit;
			}
			
			#page boundary error has occurred so display the first page of the form
			else
			{
				&load_first_page();
			}
		}
		
		#password is not valid for THIS session
		elsif ($valid_pass == -1)
		{
			#add a record to the log
			&add_log_record('auto login invalid','denied');
		
			#supplied password and stored password don't match
			&show_server_error($ERROR_NUM_INVALID_PASSWORD,"Invalid Session Password","The password supplied does not match the one associated with this session. Please verify the password and try again.", __LINE__);			
		}

		#password is not valid at all
		else
		{
			#add a record to the log
			&add_log_record('auto login invalid','denied');

			#supplied password and stored password don't match
			&show_server_error($ERROR_NUM_INVALID_PASSWORD,"Invalid Password",$form_configuration{'[MISC]'}{'InvalidPasswordError'}, __LINE__); 				
		}
		exit;				
	}
 	
 	#loop thru the submitted data searching for the action
	foreach $key (keys %submitted_data)
	{
		#all page actions are based on the FORM_ACTION parameter
	   	if($key eq 'FORM_ACTION')
		{
			#split the lines 'key=value' into (key, value) pairs
			($action, $method) = split (/\!/, $submitted_data{$key});

			#determine if a timeout value has been set for the form
			if($form_configuration{'[MISC]'}{'TimeoutValue'} ne '0')
			{
				#make sure that the session has not timed out
			   	if(($action ne 'LOGIN') && ($action ne 'DISPLAY_LOGIN') && ($action ne ''))
	 			{
					if($form_configuration{'[MISC]'}{'PasswordRequired'} eq '1')
					{
						$timed_out = &valid_session_time();
					}
	 			}
			}

			#if requesting to display the login page
			if($action eq 'DISPLAY_LOGIN')
			{
				#construct the location of our login page and attempt to display it
				$back_location = &return_full_path($form_directories{'[Forms]'}{$form_name},'login_page.html');
				if (-e $back_location)
				{
					&display_html(&reload_form_replacement($back_location,'','','[login_page]'));					}
				else
				{
					&display_login_page;
				}
				exit;
			}

			#if requesting to login
			elsif($action eq 'LOGIN')
			{
				#used for password protected surveys only!
				require rwsmd5;

				#hash the password passed in
				$tmp_hash = &HexDigest($submitted_data{'PASSWORD'});
				
				#attempt validation sending in the password hash
				$valid_pass = &validate_credentials($tmp_hash);	  
   				
				#if the password is valid
   				if ($valid_pass == 1)
				{			  
					#make sure the password has not expired
					if(&password_status($form_hash_file,$tmp_hash,0) == 0)
					{
						exit;
					}

					#update last access time
					$form_uid{'[MISC]'}{'LastAccessTime'} = time;

					#update the uid file with the password hash used to gain access
					$form_uid{'[MISC]'}{'ID'} = $tmp_hash;
														
					#write out the uid file
					&write_config(\%form_uid,$uid_file,1);
					
					#get the next page, determine if there were already submissions
					$next_page = &last_submitted_page($submitted_data{'PAGE_KEY'});
				
					#if a valid page was returned
					if ($next_page ne '0')
					{
	 					#if we have the RANDOM page value defined
						if(defined $form_configuration{'[page_' . $next_page . ']'}{'#RANDOM_ID#'})
						{
							#if we are dealing with a RANDOM page group
							if($form_configuration{'[page_' . $next_page . ']'}{'#RANDOM_ID#'} ne '-1')
							{
								#return a possible page in the random sequence
								$tmp_page = &next_random_page($form_configuration{'[page_' . $next_page . ']'}{'#RANDOM_ID#'});

								#if a URL was specified (SHOULD NOT be the case) goto that page instead
								if($tmp_page =~ /^http/)
								{
									%merged_data = &merge_submitted_data();
									&browser_redirect($tmp_page,$form_directories{'[Defaults]'}{'CGIRedirect'},\%merged_data);
									exit;  
								}
								#an html page key was returned
								else
								{
									#get the target file from the target hash
									$target_page = $form_configuration{$tmp_page}{"#SRC#"};

									#if a URL was specified goto that page instead
									if($target_page =~ /^http/)
									{
										%merged_data = &merge_submitted_data();
										&browser_redirect($target_page,$form_directories{'[Defaults]'}{'CGIRedirect'},\%merged_data);   
										exit;
									}

									#if a page was specified
									else
									{
										#concatenate the form's directory with the target page
										$target_page = &return_full_path($form_directories{'[Forms]'}{$form_configuration{'[MISC]'}{'FormName'}},$target_page);	
											
										#add log record
										&add_log_record('form access','permitted');
					
										#navigate to the appropriate page
										&display_html(&reload_form_replacement($target_page,'','',$tmp_page));

										exit;
									}
								}
							}

							#not a random page
							else
							{
								#add log record
								&add_log_record('form access','permitted');

								#get the expected file location
								$back_location = &return_full_path($form_directories{'[Forms]'}{$form_name},'page_' . $next_page . '.html');	
							
								#display the appropriate page
								&display_html(&reload_form_replacement($back_location,'','','[page_' . $next_page . ']'));

								exit;
							}
						}
						#not a random page - RANDOM PAGE KEY was not found in config file
						else
						{
							#add log record
							&add_log_record('form access','permitted');

							#get the expected file location
							$back_location = &return_full_path($form_directories{'[Forms]'}{$form_name},'page_' . $next_page . '.html');	

							#display the appropriate page
							&display_html(&reload_form_replacement($back_location,'','','[page_' . $next_page . ']'));

							exit;
						}
					}
					
					#page boundary error occurred so return the first page of the form
					else
					{
						&load_first_page();
					}
				}

				#session password is invalid
				elsif($valid_pass == -1)
				{
					#add record to log file
					&add_log_record('session password invalid','denied');

					#supplied password and stored password don't match
					&show_server_error($ERROR_NUM_INVALID_PASSWORD,"Invalid Session Password","The password supplied does not match the one associated with this session. Please verify the password and try again.", __LINE__); 				
				}
				
				#password not valid
				else
				{
					#add record to log file
					&add_log_record('password invalid','denied');

					#supplied password and stored password don't match
					&show_server_error($ERROR_NUM_INVALID_PASSWORD,"Invalid Password",$form_configuration{'[MISC]'}{'InvalidPasswordError'}, __LINE__);				
				}

				#we may exit if not already as login procedure has completed
				last;
			}

			#if submitted from the pause page
			elsif($action eq 'SEND_EMAIL')
			{
				#if the user clicked back
				if((exists $submitted_data{'BACK'}) || ((exists $submitted_data{'BACK.x'}) && (exists $submitted_data{'BACK.y'})))
				{
					#get the page they clicked pause from
					$next_page = &last_submitted_page($submitted_data{'PAGE_KEY'});
					
					#if a valid page was returned
					if ($next_page ne '0')
					{
						#remove the last submitted page as we are going back to it
						&remove_from_submitted_pages;
									  
						#construct the location of our last page
						$back_location = &return_full_path($form_directories{'[Forms]'}{$form_name},'page_' . $next_page . '.html');
						
						#reload the last page submitted
						&display_html(&reload_form_replacement($back_location,'','','[page_' . $next_page . ']'));

						exit;
					}
					
					#page boundary error occurred so go to the first page of the form
					else
					{
						&load_first_page();
					}
				}

				#requesting to send email, validate the email address before sending
				elsif(&validate_email_address($submitted_data{'EMAIL'}) eq '1')
				{
					#get http, https, etc
					$full_url = $data_script_location . '?FORM=' . $form_configuration{'[MISC]'}{'FormName'} . '&UID=' . $session_uid;

					#if attempt email operation is successful
					if(&smtp_mail($submitted_data{'EMAIL'},$form_configuration{'[MISC]'}{'EmailFrom'},$form_configuration{'[MISC]'}{'EmailSubject'},$form_configuration{'[MISC]'}{'SMTPServer'},$form_configuration{'[MISC]'}{'PortNumber'},$form_configuration{'[MISC]'}{'EmailBody'} . "\n\n" . $full_url) eq '1')
					{
						#add record to log file
						&add_log_record('pause page email','success');
						&general_error_screen("Email Attempt Successful", localtime() . ": Email message was sent successfully to <B>" . $submitted_data{'EMAIL'} . "</B>.",'',1,$data_script_location);
					}

					#email attempt failed
					else
					{
						&general_error_screen("Email Attempt Failed","<B>Module:</B> RWS3<BR><B>Line:</B> " . __LINE__ . "<BR><B>Details:</B> An error occurred sending the email message.  Please contact the system administrator regarding the email failure.",$form_configuration{'[MISC]'}{'AdminAddress'},0,$data_script_location);
					}
					exit;
				}					
				
				#the email address is not valid
				else
				{
					&general_error_screen("Invalid Email Address","<B>Module:</B> RWS3<BR><B>Line:</B> " . __LINE__ . "<BR><B>Details:</B> The email address supplied is invalid. Please check the address and try again.",$form_configuration{'[MISC]'}{'AdminAddress'},0,$data_script_location);
					exit;
				}
			}

			#if submitting from a regular page
			elsif($action eq 'BRANCH')
			{	
				#if the user clicked the back button
				if((exists $submitted_data{'BACK'}) || ((exists $submitted_data{'BACK.x'}) && (exists $submitted_data{'BACK.y'})))
				{
					#if not clicking back from confirm, pause, or error
					if (($submitted_data{'PAGE_KEY'} ne '[confirmation_page]') && ($submitted_data{'PAGE_KEY'} ne '[pause_page]') && ($submitted_data{'PAGE_KEY'} ne '[error_page]') && $submitted_data{'PAGE_KEY'} ne '')
					{
						#add the filled in values to the uid file (for fill in forms)
						%form_uid = &append_hash(\%form_uid,$submitted_data{'PAGE_KEY'},\%submitted_data);
		
						#write out the uid file
						&write_config(\%form_uid,$uid_file,1);
					}

					#get the last submitted page
					$next_page = &last_submitted_page($submitted_data{'PAGE_KEY'});

					#if a valid page was returned					
					if ($next_page ne '0')
					{
						#remove the last submitted page as we are going back to it
						&remove_from_submitted_pages;
									  
						#construct the location of our last page
						$back_location = &return_full_path($form_directories{'[Forms]'}{$form_name},'page_' . $next_page . '.html');
						
						#reload the last page submitted
						&display_html(&reload_form_replacement($back_location,'','','[page_' . $next_page . ']'));
					}
					#page boundary error occurred so go to the first page of the form
					else
					{
						&load_first_page();
					}
				}

				#if the user clicked a pause button on the form
				elsif((exists $submitted_data{'PAUSE'}) || ((exists $submitted_data{'PAUSE.x'}) && (exists $submitted_data{'PAUSE.y'})))
				{
					#push the page onto the queue
					&add_to_submitted_pages($submitted_data{'PAGE_KEY'});

					#add the filled in values to the uid file (for fill in forms)
					%form_uid = &append_hash(\%form_uid,$submitted_data{'PAGE_KEY'},\%submitted_data);
					
					#write out the uid file
					&write_config(\%form_uid,$uid_file,1);

					#add log record
					&add_log_record('form paused','permitted');

					#construct the location of our last page
					$back_location = &return_full_path($form_directories{'[Forms]'}{$form_name},'pause_page.html');
					
					#reload the last page submitted
					&display_html(&reload_form_replacement($back_location,'','',$submitted_data{'PAGE_KEY'}));

					#write in the new active page - pause page
					$form_uid{'[MISC]'}{'ActiveKey'} = '[pause_page]';
					
					#write out the uid file
					&write_config(\%form_uid,$uid_file,1);

					exit;
				}

				#if the user clicked the reset button then reload with original form values
				elsif((exists $submitted_data{'RESET'}) || ((exists $submitted_data{'RESET.x'}) && (exists $submitted_data{'RESET.y'})))
				{
					#if form uid data for this page exists
					if(exists $form_uid{$submitted_data{'PAGE_KEY'}})
					{
						#delete the form uid data for this page
						delete $form_uid{$submitted_data{'PAGE_KEY'}};
						
						#write out a uid file
						&write_config(\%form_uid,$uid_file,1);
					}

					#turns '[Page_X]' into X]
					$target_page = (split(/\_/,$submitted_data{'PAGE_KEY'}))[1];

					#turns 'X]' into X
					$target_page = (split(/\]/,$target_page))[0];

					#construct the location of our current page
					$back_location = &return_full_path($form_directories{'[Forms]'}{$form_name},'page_' . $target_page . '.html');

					#redisplay our current page
					&display_html(&reload_form_replacement($back_location,'','',$submitted_data{'PAGE_KEY'}));
					exit;
				}

				#if the user is requesting a basic submit
			   	else
				{	
					#make sure that data was valid
				   	if(&validate_responses(\%submitted_data) == '1')
					{
						#see if the user has timed out
						if($timed_out ne '1')
						{
							#push the page onto the queue
							&add_to_submitted_pages($submitted_data{'PAGE_KEY'});

							#add the filled in values to the uid file (for fill in forms)
							%form_uid = &append_hash(\%form_uid,$submitted_data{'PAGE_KEY'},\%submitted_data);
							
							#write out the uid file
							&write_config(\%form_uid,$uid_file,1);

							#construct the location of our login page and display it
							$back_location = &return_full_path($form_directories{'[Forms]'}{$form_name},'login_page.html');
							if (-e $back_location)
							{
								&display_html(&reload_form_replacement($back_location,'','','[login_page]'));					}
							else
							{
								&display_login_page;
							}
							exit;
						}
						#form has NOT timed out
						else
						{	
							#add the filled in values to the uid file (for fill in forms)
							%form_uid = &append_hash(\%form_uid,$submitted_data{'PAGE_KEY'},\%submitted_data);
							
							#write out the uid file
							&write_config(\%form_uid,$uid_file,1);

							#push the page onto the queue
							&add_to_submitted_pages($submitted_data{'PAGE_KEY'});

							#perform the branch operation
							$current_page = (&perform_branch($submitted_data{'PAGE_KEY'},\%submitted_data));

							#if the survey is completed
							if($current_page =~ /complete\_page/)
							{				
								#if the lock file does not exist, create it
								if (!(-e $uid_lock_file))
								{
									if (open (LOCK_FILE, ">$uid_lock_file")) 
									{
										close(LOCK_FILE);
									}
								}
										
								#add the form data to the data record
								if(&add_data_records == 1)
								{
									#add log record for completed submission
									&add_log_record('form completed','permitted');

									#send a submission email if all requirements are met
									if(($form_configuration{'[MISC]'}{'SendEmail'} eq '1') && ($form_configuration{'[MISC]'}{'RecipientAddress'} ne ''))
									{
										if($form_configuration{'[MISC]'}{'SMTPServer'} ne '')
										{
												if($form_configuration{'[MISC]'}{'AdminAddress'} ne '')
												{
													$email_body = &construct_email_body();
													if(&smtp_mail($form_configuration{'[MISC]'}{'RecipientAddress'},$form_configuration{'[MISC]'}{'AdminAddress'},"Automated Mailing - Form Submission [" . $form_configuration{'[MISC]'}{'FormName'} . "]",$form_configuration{'[MISC]'}{'SMTPServer'},$form_configuration{'[MISC]'}{'PortNumber'},$email_body))
													{
														&add_log_record('submission email','successful');
													}
													else
													{
														&add_log_record('submission email','failed');
													}
												}
												else
												{
													&add_log_record('submission email','failed (no admin address)');
												}
										}
										else
										{
											&add_log_record('submission email','failed (no server name)');
										}
									}

									#remove the uid file after submission is COMPLETE
								   	unlink $uid_file;

									#clean up the lock file if it exists
									if(-e $uid_lock_file)
									{
										unlink $uid_lock_file; 
									}

									#remove any old UID files
									&remove_old_uid_files;
								}

								#adding data records failed
								else
								{
									#clean up the lock file if it exists
									if(-e $uid_lock_file)
									{
										unlink $uid_lock_file; 
									}
								}
							}
							#a non-success page was successfully submitted
							else
							{
								&add_log_record($submitted_data{'PAGE_KEY'} . ' submitted','permitted');
							}
						}
					}
				}
			}
		}
	}
}

########################################################################################
# 	FUNCTION THAT RETURNS THE LAST SUBMITTED PAGE									   #
#	USE: $last_page_index = &last_submitted_page($submitted{page_key});    	       	   #		
########################################################################################
sub last_submitted_page
{
	my $current_key = $_[0];
	my @pages = ();
	my $page = "";
	my $last_page = 0;
	my $pop_required = 0;
	my $same_page = 1;
	my $current_page = "";

	if(($form_uid{'[MISC]'}{'SubmittedPages'} eq '0') || ($form_uid{'[MISC]'}{'SubmittedPages'} eq ''))
	{
		return(0);
	}
	else
	{
		if ($current_key ne '')
		{
			#turns '[Page_X]' into X]
			$current_page = (split(/\_/,$current_key))[1];

			#turns 'X]' into X
			$current_page = (split(/\]/,$current_page))[0];
		}

		while ($same_page == 1) 
		{
			#split the submitted pages string into hash
			@pages = split (/\,/, $form_uid{'[MISC]'}{'SubmittedPages'});

			#get the previous page in the sequence
			$last_page = $pages[$#pages];
			
			#if the page you are on and the previous page are the same, set the pop flag		
			if ($last_page eq $current_page)
			{
				&remove_from_submitted_pages;
				$same_page = 1;
			}
			else
			{
				$same_page = 0;	
			}
		} 

		#return the last page
		return($pages[$#pages]);
	}
}

########################################################################################
# 	FUNCTION THAT RETURNS THE NEXT PAGE												   #
#	USE: $next_page_location = &get_next_page();					       	       	   #		
########################################################################################
sub get_next_page
{
	my $next_page_index = 0;
	my $location = "";

	#get the last submitted page and increment it
	$next_page_index = &last_submitted_page;
	$next_page_index++;

	#get the expected file location
	$location = &return_full_path($form_directories{'[Forms]'}{$form_configuration{'[MISC]'}{'FormName'}},'page_' . $next_page_index . '.html');

	return ($location);
}

########################################################################################
# 	FUNCTION GENERATES A UID FILE FOR THE USER 		       		       				   #		
#	USE: &generate_uid_file();					       	       						   #		
########################################################################################
sub generate_uid_file
{
	if($session_uid ne '')
	{
		$form_uid{'[MISC]'}{'IPAddress'} = $ENV{'REMOTE_ADDR'};
		$form_uid{'[MISC]'}{'ID'} = '';
		$form_uid{'[MISC]'}{'LastAccessTime'} = time;
		$form_uid{'[MISC]'}{'ExpireTime'} = $form_configuration{'[MISC]'}{'TimeoutValue'};
		$form_uid{'[MISC]'}{'SubmittedPages'} = '0';
		$form_uid{'[MISC]'}{'FormName'} = $form_configuration{'[MISC]'}{'FormName'};
		$form_uid{'[MISC]'}{'ActiveKey'} = '';

		$uid_file = &return_full_path($form_directories{'[Forms]'}{$form_configuration{'[MISC]'}{'FormName'}},$session_uid);
		$uid_file .= '.uid';

		#set the file permissions
		chmod(0600, $uid_file);

	}			
	return(1);
}

########################################################################################
# 	FUNCTION THAT VALIDATES SESSION INACTIVITY										   #
#	USE: &valid_session_time();					       	       						   #		
########################################################################################
sub valid_session_time
{
	my $cur_time = 0;

	if($uid_file eq '')
	{
		return (0);
	}
 
	$cur_time = time;

	#if valid time then update the file
	if (abs($cur_time - $form_uid{'[MISC]'}{'LastAccessTime'}) < ($form_configuration{'[MISC]'}{'TimeoutValue'} * 60))
	{
		$form_uid{'[MISC]'}{'LastAccessTime'} = $cur_time;
		&write_config(\%form_uid,$uid_file,1);
		return (1);
	}
	else
	{
 		return (0);
	}
}

########################################################################################
# 	FUNCTION THAT ADDS TO THE SUBMITTED PAGE LIST									   #
#	USE: &add_to_submitted_pages($Page_Key);					       	       		   #	
########################################################################################
sub add_to_submitted_pages
{
	my $page_key = $_[0];
	my $page_index = "";
	my @pages = ();

	#turns '[Page_X]' into X]
	$page_index = (split(/\_/,$page_key))[1];

	#turns 'X]' into X
	$page_index = (split(/\]/,$page_index))[0];
	
	#exit if the index is not numeric
	if ($page_index !~ /^-?\d/) 
	{
		return (1);
	}
		   
	#update the uid file
	if(($form_uid{'[MISC]'}{'SubmittedPages'} eq '0') || ($form_uid{'[MISC]'}{'SubmittedPages'} eq ''))
	{
		$form_uid{'[MISC]'}{'SubmittedPages'} = $page_index;
	}
	else
	{
		#store the pages in a hash
		@pages = split(/\,/,$form_uid{'[MISC]'}{'SubmittedPages'});
 
		#add our latest page
		push (@pages,$page_index);

		#create the new string with the last page added
		$form_uid{'[MISC]'}{'SubmittedPages'} = join(',',@pages);
	}
	
	#write out the uid file
	&write_config(\%form_uid,$uid_file,1);

   	return (1);
}

########################################################################################
# 	FUNCTION THAT REMOVES THE LAST SUBMITTED PAGE 									   #
#	USE: &remove_from_submitted_pages();					       	       			   #		
########################################################################################
sub remove_from_submitted_pages
{
	my @pages = ();
 
	#update the uid file
	if(($form_uid{'[MISC]'}{'SubmittedPages'} eq '0') || ($form_uid{'[MISC]'}{'SubmittedPages'} eq ''))
	{
		return (0);
	}
	else
	{
		#store the pages in a hash
		@pages = split(/\,/,$form_uid{'[MISC]'}{'SubmittedPages'});
 
		#remove the last page
		pop (@pages);

		#create the new string with the last page added
		$form_uid{'[MISC]'}{'SubmittedPages'} = join(',',@pages);
	}
	
	#write out the uid file
	&write_config(\%form_uid,$uid_file,1);

   	return (1);
}
########################################################################################
# 	FUNCTION THAT DISPLAYS HTML OF A GENERIC SCREEN FILLED WITH PARAMETERS 			   #
#	USE: &general_screen($title,$header,$msg,$ok,$cancel,$action,$button_align);	   #		
########################################################################################
sub general_screen
{
	my $html_title = $_[0];
	my $header_text = $_[1];
	my $msg_text = $_[2];
	my $ok_text = $_[3];
	my $cancel_text = $_[4];
	my $action_text = $_[5];
	my $button_align = $_[6];
	my $html_text = "";
		
	$html_text = "<HTML><HEAD>\n";
	$html_text .= "<META HTTP-EQUIV=\"pragma\" CONTENT=\"no-cache\">\n";
	$html_text .= "<TITLE>RWS Form Message</TITLE>\n";
	$html_text .= "<SCRIPT LANGUAGE=\"JAVASCRIPT\">\n";
   	$html_text .= "function perform_navigate(cancel)\n";
	$html_text .= "{\n";
	$html_text .= "if(cancel == 0)\n";
	$html_text .= "{\n";
	$html_text .= "document.RWSADMIN.submit();\n";
	$html_text .= "}\n";
	$html_text .= "else\n";
	$html_text .= "{\n";
	$html_text .= "document.RWSADMIN.FORM_ACTION.value = \"MAIN!\";\n";
	$html_text .= "document.RWSADMIN.submit();\n";
	$html_text .= "}\n";
	$html_text .= "}\n";
	$html_text .= "</SCRIPT>\n";
	$html_text .= "</HEAD>\n";
	$html_text .= "<BODY TOPMARGIN=20 BGCOLOR=\"#FFFFFF\" TEXT=\"#FFFFFF\" LINK=\"#000000\" VLINK=\"#000000\">\n";
	$html_text .= "<CENTER>\n";
	$html_text .= "<FORM NAME=\"RWSADMIN\" ACTION=\"@*(data)@*(form_query)@*(uid)\" METHOD=\"POST\">\n";
    $html_text .= "<TABLE WIDTH=\"600\" BORDER=1 CELLPADDING=20 BGCOLOR=\"#C0C0C0\">\n";
    	$html_text .= "<TR>\n";
    		$html_text .= "<TD BGCOLOR=\"#2C3D78\" ALIGN=\"CENTER\"><FONT FACE=\"Verdana,Arial,Helvetica\" SIZE=2><B>\n";
      			$html_text .= "<H2>@*(html_title)</H2>\n";
				$html_text .= "<BR><BR>\n";
				$html_text .= "<TABLE BORDER=0>\n";
				    $html_text .= "<TR>\n";
        				$html_text .= "<TD WIDTH=\"550\" ALIGN=\"LEFT\" COLSPAN=2><FONT FACE=\"Verdana,Arial,Helvetica\" SIZE=4><B>@*(header)</B></FONT><BR><HR></HR>\n";
			        	$html_text .= "</TD>\n";
			        $html_text .= "</TR>\n";
				    $html_text .= "<TR>\n";
        				$html_text .= "<TD WIDTH=\"550\"><FONT FACE=\"Verdana,Arial,Helvetica\" SIZE=2>@*(msg_text)</FONT>\n";
				        $html_text .= "</TD>\n";
			        $html_text .= "</TR>\n";
					$html_text .= "<TR>\n";
						$html_text .= "<TD WIDTH=\"550\" COLSPAN=2>&nbsp;\n";
				       	$html_text .= "</TD>\n";
			        $html_text .= "</TR>\n";
			        $html_text .= "<TR>\n";
				        $html_text .= "<TD WIDTH=\"550\" COLSPAN=2 ALIGN=\"@*(button_align)\"><INPUT TYPE=\"BUTTON\" NAME=\"OK\" VALUE=\"@*(ok_text)\" onClick=\"perform_navigate(0);\" style=\"width: 100\"></INPUT>\n";
						if($cancel_text ne "")
						{
							$html_text .= "&nbsp;<INPUT TYPE=\"BUTTON\" NAME=\"CANCEL\" VALUE=\"@*(cancel_text)\" onClick=\"perform_navigate(1);\" style=\"width: 100\"></INPUT>\n";
						}
				       	$html_text .= "</TD>\n";
			        $html_text .= "</TR>\n";
			   	$html_text .= "</TABLE>\n";
				$html_text .= "\n";
      			$html_text .= "</B></FONT>\n";
    		$html_text .= "</TD>\n";
    	$html_text .= "</TR>\n";
    $html_text .= "</TABLE>\n";
	$html_text .= "<INPUT TYPE=\"HIDDEN\" NAME=\"FORM_ACTION\" VALUE=\"@*(action)\"></INPUT>\n";
    $html_text .= "</FORM>\n";
    $html_text .= "&nbsp;<BR>\n";

	$html_text .= "<FONT FACE=\"Verdana,Arial,Helvetica\" SIZE=1 COLOR=\"#000000\">\n";
	$html_text .= "<A HREF=http://www.principiaproducts.com/info/copyrght.htm>&copy; 2002 Principia Products. All Rights Reserved.</A>\n";
	$html_text .= "</FONT>\n";
	$html_text .= "</CENTER>\n";
	$html_text .= "</BODY></HTML>\n";         

	#insert the admin script into form '@*()'
	$html_text =~ s/\@\*\(data\)/$data_script_location/g;

	#insert the title into our form '@*()'
	$html_text =~ s/\@\*\(html_title\)/$html_title/g;
	
	#insert the header into our form '@*()'
	$html_text =~ s/\@\*\(header\)/$header_text/g;
	
	#insert the message/question/confirmation into our form '@*()'
	$html_text =~ s/\@\*\(msg_text\)/$msg_text/g;														

	#insert the ok text into our form '@*()'
	$html_text =~ s/\@\*\(ok_text\)/$ok_text/g;
	
	#insert the cancel text into our form '@*()'
	$html_text =~ s/\@\*\(cancel_text\)/$cancel_text/g;
																						  
	#insert the action into our form '@*()'
	$html_text =~ s/\@\*\(action\)/$action_text/g;

	#insert the action into our form '@*()'
	$html_text =~ s/\@\*\(button_align\)/$button_align/g;
	
	#insert the uid into our form '@*()'
	if($session_uid ne '')
	{
		$html_text =~ s/\@\*\(uid\)/\&UID\=$session_uid/g;
	}
	else
	{
		$html_text =~ s/\@\*\(uid\)//g;
	}
 		
 	#insert the uid into our form '@*()'
	if(exists $form_configuration{'[MISC]'}{'FormName'})
	{
		$html_text =~ s/\@\*\(form_query\)/\?FORM\=$form_configuration{'[MISC]'}{'FormName'}/g;
	}
	else
	{
		$html_text =~ s/\@\*\(form_query\)//g;
	}
	
	#insert the image server script into form '@*()'
	$html_text =~ s/\@\*\(img\)/$form_directories{'[Defaults]'}{'ImageScript'}/g;
								   
	&display_html($html_text);

	return 1;
}

########################################################################################
# 	FUNCTION THAT DISPLAYS A LOGIN PAGE 											   #
#	USE: &display_login_page();					       	       						   #		
########################################################################################
sub display_login_page 
{
	my $html_text = "";
 
	$html_text = "<HTML><HEAD>\n";
	$html_text .= "<META HTTP-EQUIV=\"pragma\" CONTENT=\"no-cache\">\n";
	$html_text .= "<TITLE>RWS Administration Control Panel</TITLE>\n";
	$html_text .= "</HEAD>\n";
	$html_text .= "<BODY TOPMARGIN=20 BGCOLOR=\"#FFFFFF\" TEXT=\"#FFFFFF\" LINK=\"#000000\" VLINK=\"#000000\">\n";
	$html_text .= "<CENTER>\n";
	$html_text .= "<FORM NAME=\"RWSADMIN\" ACTION=\"@*(data)@*(form_query)@*(uid)\" METHOD=\"POST\">\n";
    $html_text .= "<TABLE WIDTH=\"600\" BORDER=1 CELLPADDING=20 BGCOLOR=\"#C0C0C0\">\n";
    	$html_text .= "<TR>\n";
    		$html_text .= "<TD BGCOLOR=\"#2C3D78\" ALIGN=\"CENTER\"><FONT FACE=\"Verdana,Arial,Helvetica\" SIZE=2><B>\n";
      			$html_text .= "<H2>Remark Web Survey<SUP>&reg;</SUP> 3.0 <BR>@*(form) Login</H2>\n";
				$html_text .= "<BR><BR>\n";
				$html_text .= "<TABLE BORDER=0>\n";
				    $html_text .= "<TR>\n";
        				$html_text .= "<TD WIDTH=\"550\" ALIGN=\"LEFT\" COLSPAN=2><FONT FACE=\"Verdana,Arial,Helvetica\" SIZE=4><B>Credentials</B></FONT><BR><HR></HR>\n";
			        	$html_text .= "</TD>\n";
			        $html_text .= "</TR>\n";
				    $html_text .= "<TR>\n";
        				$html_text .= "<TD WIDTH=\"275\"><FONT FACE=\"Verdana,Arial,Helvetica\" SIZE=2><B>Form Password:</B></FONT>\n";
				        $html_text .= "</TD>\n";
				        $html_text .= "<TD WIDTH=\"275\"><INPUT TYPE=\"PASSWORD\" NAME=\"PASSWORD\" SIZE=\"45\"></INPUT>\n";
				        $html_text .= "</TD>\n";
			        $html_text .= "</TR>\n";
					$html_text .= "<TR>\n";
						$html_text .= "<TD WIDTH=\"550\" COLSPAN=2>\n";
				       	$html_text .= "</TD>\n";
			        $html_text .= "</TR>\n";
			        $html_text .= "<TR>\n";
				        $html_text .= "<TD WIDTH=\"550\" COLSPAN=2 ALIGN=\"RIGHT\"><INPUT TYPE=\"SUBMIT\" NAME=\"LOGIN\" VALUE=\"Login\" style=\"width: 125\"></INPUT>\n";
				       	$html_text .= "</TD>\n";
			        $html_text .= "</TR>\n";
			   	$html_text .= "</TABLE>\n";
      			$html_text .= "</B></FONT>\n";
    		$html_text .= "</TD>\n";
    	$html_text .= "</TR>\n";
    $html_text .= "</TABLE>\n";
	$html_text .= "<INPUT TYPE=\"HIDDEN\" NAME=\"FORM_ACTION\" VALUE=\"LOGIN\!\"></INPUT>\n";
    $html_text .= "</FORM>\n";
    $html_text .= "&nbsp;<BR>\n";

	$html_text .= "<FONT FACE=\"Verdana,Arial,Helvetica\" SIZE=1 COLOR=\"#000000\">\n";
	$html_text .= "<A HREF=http://www.principiaproducts.com/info/copyrght.htm>&copy; 2002 Principia Products. All Rights Reserved.</A>\n";
	$html_text .= "</FONT>\n";
	$html_text .= "</CENTER>\n";
	$html_text .= "</BODY></HTML>\n";         
	
	#insert the uid into our form '@*()'
	if($session_uid ne '')
	{
		$html_text =~ s/\@\*\(uid\)/\&UID\=$session_uid/g;
	}
	else
	{
		$html_text =~ s/\@\*\(uid\)//g;
	}

	#insert the uid into our form '@*()'
	if(exists $form_configuration{'[MISC]'}{'FormName'})
	{
		$html_text =~ s/\@\*\(form_query\)/\?FORM\=$form_configuration{'[MISC]'}{'FormName'}/g;
	}
	else
	{
		$html_text =~ s/\@\*\(form_query\)//g;
	}

	#insert the image server script into form '@*()'
	$html_text =~ s/\@\*\(img\)/$form_directories{'[Defaults]'}{'ImageScript'}/g;

	#insert the data script into form '@*()'
	$html_text =~ s/\@\*\(data\)/$data_script_location/g;
	
	#insert the form name into the error message form '@*()'
	$html_text =~ s/\@\*\(form\)/[$form_configuration{'[MISC]'}{'FormName'}] Form/g;

	&display_html($html_text);

	return (1);
}

########################################################################################
# 	FUNCTION THAT PRINTS THE SUBMISSION DETAILS   									   #
#	USE: &print_submission(%data_hash);					       	       				   #		
########################################################################################
sub print_submission
{
	my %submit = %{$_[0]};
	my $output = "";
	my $key = "";

	$output = '<CENTER><H><B>REMARK WEB SURVEY&reg; 3.0 SUBMITTED DATA</B></H><BR></CENTER>';
	foreach $key (sort keys %submit)
 	{
 		$output .= $key . '=' . $submit{$key} . '<BR>';
 	}
 	&display_html($output);
 	exit;	
}

########################################################################################
# 	FUNCTION THAT DETERMINES IF DATA IS VALID    									   #
#	USE: $valid = &validate_responses(%data);					       	       		   #			
########################################################################################
sub validate_responses
{
 	my %data = %{$_[0]};
 	my $key = "";
	my $question_index = "";
	my $last_index = "";
	my $tmp_var = "";
	my $select_count = 0;
	my $current_group = '0000';
	my $question_type = "";
	my $reload_location = "";
	my $page_src = "";
	my $multiple_str = "";
	my $prefix = "";
	my $counter = 0;
	my $element = "";
	my $required_ok = 0;

	#&print_submission;	

	#check for required fields
	if(defined $data{'QUESTION_START'})
	{
		#loop thru the questions on the page
		for ($counter = $data{'QUESTION_START'}; $counter <= $data{'QUESTION_END'}; $counter++)
		{
			#calculate correct element
			$element = sprintf("%04d",$counter);

			#if the item is required  
			if($form_configuration{'[Questions]'}{'Q' . $element . '_REQUIRED'} eq '1') 
			{
				$required_ok = 0;
				
				#loop thru all the submitted data
			 	foreach $key (sort keys %data)
			 	{
			 		#if the $key starts with a 'Q'
				   	next if($key !~ /^Q/);
		 			
		 			$prefix = 'Q' . $element . '_';
		 							 
					#check to see that at least one answer was selected 
					if($key =~ /$prefix/)
					{
						#key was answered - make sure with something
						if($data{$key} ne '')
						{
							$required_ok = 1;
							last;
						}
						else
						{
							last;
						}
					}
				}
		
				#reload the page and display the error
				if($required_ok == 0)
				{
					#turns '[Page_X]' into X]
					$page_src = (split(/\_/,$data{'PAGE_KEY'}))[1];

					#turns 'X]' into X
					$page_src = (split(/\]/,$page_src))[0];

					#construct the location of our last page
					$reload_location = &return_full_path($form_directories{'[Forms]'}{$form_configuration{'[MISC]'}{'FormName'}},'page_' . $page_src . '.html');

					#add the filled in values to the uid file (for fill in forms)
					%form_uid = &append_hash(\%form_uid,$data{'PAGE_KEY'},\%data);
					
					#write out the uid file
					&write_config(\%form_uid,$uid_file,1);

					#redisplay the page with the error message on it
					&display_html(&reload_form_replacement($reload_location,$form_configuration{'[Questions]'}{'Q' . $element . '_REQUIRED_ERR'} . '<BR><LI><FONT NAME="ARIAL,VERDANA,HELVETICA" SIZE="2"><A HREF=#Q' . $form_configuration{'[Questions]'}{'Q' . $element . '_GROUP_ID'} . '>' . $form_configuration{'[Questions]'}{'Q' . $form_configuration{'[Questions]'}{'Q' . $element . '_GROUP_ID'} . '_NAME'} . ': ' . $form_configuration{'[Questions]'}{'Q' . $element . '_TEXT'} . '</A></FONT></LI>',$form_configuration{'[Questions]'}{'Q' . $element . '_GROUP_ID'},$data{'PAGE_KEY'}));

					return(0);
				}
			}
		} 
	}

	#loop thru all the submitted data
 	foreach $key (sort keys %data)
 	{
		#if the $key starts with a 'Q'
	   	next if($key !~ /^Q/);
								 
		#grab the question number - turns 'QX_XYZ=123' into QX
		$tmp_var = (split(/\_/,$key))[0];
			
		#turns 'QX' into X
		$question_index = substr($tmp_var,1);

		#if the group changes - check for errors
		if($current_group ne '0000')
		{
			if($current_group ne $form_configuration{'[Questions]'}{'Q' . $question_index . '_GROUP_ID'})		
			{
				#turns '[Page_X]' into X]
				$page_src = (split(/\_/,$data{'PAGE_KEY'}))[1];

				#turns 'X]' into X
				$page_src = (split(/\]/,$page_src))[0];

				#construct the location of our last page
				$reload_location = &return_full_path($form_directories{'[Forms]'}{$form_configuration{'[MISC]'}{'FormName'}},'page_' . $page_src . '.html');

				#if no items were selected and there was a problem, report it
				if(($form_configuration{'[Questions]'}{'Q' . $last_index . '_REQUIRED'} eq '1') && ($select_count == 0))
				{
					#add the filled in values to the uid file (for fill in forms)
					%form_uid = &append_hash(\%form_uid,$data{'PAGE_KEY'},\%data);
					
					#write out the uid file
					&write_config(\%form_uid,$uid_file,1);

					#redisplay the page with the error message on it
					&display_html(&reload_form_replacement($reload_location,$form_configuration{'[Questions]'}{'Q' . $last_index . '_REQUIRED_ERR'} . '<BR><LI><FONT NAME="ARIAL,VERDANA,HELVETICA" SIZE="2"><A HREF=#Q' . $form_configuration{'[Questions]'}{'Q' . $last_index . '_GROUP_ID'} . '>' . $form_configuration{'[Questions]'}{'Q' . $form_configuration{'[Questions]'}{'Q' . $last_index . '_GROUP_ID'} . '_NAME'} . ': ' . $form_configuration{'[Questions]'}{'Q' . $last_index . '_TEXT'} . '</A></FONT></LI>',$form_configuration{'[Questions]'}{'Q' . $last_index . '_GROUP_ID'},$data{'PAGE_KEY'}));

					return(0);
				}
				#check for max length problems
				elsif($select_count > 0)
				{
					if(($select_count > $form_configuration{'[Questions]'}{'Q' . $last_index . '_MAX_RESPONSE'}) && ($form_configuration{'[Questions]'}{'Q' . $last_index . '_MAX_RESPONSE'} > 0))
					{
						#add the filled in values to the uid file (for fill in forms)
						%form_uid = &append_hash(\%form_uid,$data{'PAGE_KEY'},\%data);
						
						#write out the uid file
						&write_config(\%form_uid,$uid_file,1);
								 
						#if dealing with a text field use the MAX LENGTH value else use MAX RESPONSE
						if($question_type eq 'TEXT')
						{
							#redisplay the page with the error message on it
							&display_html(&reload_form_replacement($reload_location,$form_configuration{'[Questions]'}{'Q' . $last_index . '_MAXLEN_ERR'} . '<BR><LI><FONT NAME="ARIAL,VERDANA,HELVETICA" SIZE="2"><A HREF=#Q' . $form_configuration{'[Questions]'}{'Q' . $last_index . '_GROUP_ID'} . '>' . $form_configuration{'[Questions]'}{'Q' . $form_configuration{'[Questions]'}{'Q' . $last_index . '_GROUP_ID'} . '_NAME'} . ': ' . $form_configuration{'[Questions]'}{'Q' . $last_index . '_TEXT'} . '</A></FONT></LI>',$form_configuration{'[Questions]'}{'Q' . $last_index . '_GROUP_ID'},$data{'PAGE_KEY'}));
						}
						else
						{
							#redisplay the page with the error message on it
							&display_html(&reload_form_replacement($reload_location,$form_configuration{'[Questions]'}{'Q' . $last_index . '_MAXRESPONSE_ERR'} . '<BR><LI><FONT NAME="ARIAL,VERDANA,HELVETICA" SIZE="2"><A HREF=#Q' . $form_configuration{'[Questions]'}{'Q' . $last_index . '_GROUP_ID'} . '>' . $form_configuration{'[Questions]'}{'Q' . $form_configuration{'[Questions]'}{'Q' . $last_index . '_GROUP_ID'} . '_NAME'} . ': ' . $form_configuration{'[Questions]'}{'Q' . $last_index . '_TEXT'} . '</A></FONT></LI>',$form_configuration{'[Questions]'}{'Q' . $last_index . '_GROUP_ID'},$data{'PAGE_KEY'}));
						}
						return(0);
					}
				}
				#reset flags before a new group
				$select_count = 0;
			}
		}

		#store the group index
		$current_group = $form_configuration{'[Questions]'}{'Q' . $question_index . '_GROUP_ID'};

		#store the question type
		$question_type = $form_configuration{'[Questions]'}{'Q' . $question_index . '_TYPE'};
	
		$last_index = $question_index;

		if($question_type eq 'TEXT')
		{
			#determine if there IS text in the text box
			if($key eq 'Q' . $question_index . '_RWS_TEXT')
			{ 
				if((defined $data{$key}) && ($data{$key} ne ''))
				{
					$select_count = length($data{$key});
				}
			}
		}	
		elsif($question_type eq 'RADIO')
		{
			if($key eq 'Q' . $question_index . '_RWS_RADIO')
			{ 
				if(defined $data{$key})
				{
					$select_count++;
				}
			}		
		}
		elsif($question_type eq 'CHECKBOX')
		{
			#determine if there IS a checkbox checked
			if(lc($data{$key}) eq 'on')
			{
				$select_count++;
			}
		}
		elsif($question_type eq 'LIST')
		{
			#constuct would be name in case a multiple list
			$multiple_str = 'Q' . $question_index . '_' . $CGI_MPD;
					 
			#determine if the list item has a value
			if(($key eq 'Q' . $question_index . '_RWS_RADIO') || ($key =~ /$multiple_str/))
			{ 
				if(defined $data{$key})
				{
					$select_count++;
				}
			}
		}	
 	}

	#account for last element!
	if($current_group ne '0000')
	{
		#turns '[Page_X]' into X]
		$page_src = (split(/\_/,$data{'PAGE_KEY'}))[1];

		#turns 'X]' into X
		$page_src = (split(/\]/,$page_src))[0];

		#construct the location of our last page
		$reload_location = &return_full_path($form_directories{'[Forms]'}{$form_configuration{'[MISC]'}{'FormName'}},'page_' . $page_src . '.html');

		#if no items were selected and there was a problem, report it
		if(($form_configuration{'[Questions]'}{'Q' . $question_index . '_REQUIRED'} eq '1') && ($select_count == 0))
		{
			#add the filled in values to the uid file (for fill in forms)
			%form_uid = &append_hash(\%form_uid,$data{'PAGE_KEY'},\%data);
			
			#write out the uid file
			&write_config(\%form_uid,$uid_file,1);

			#redisplay the page with the error message on it
			&display_html(&reload_form_replacement($reload_location,$form_configuration{'[Questions]'}{'Q' . $question_index . '_REQUIRED_ERR'} . '<BR><LI><FONT NAME="ARIAL,VERDANA,HELVETICA" SIZE="2"><A HREF=#Q' . $form_configuration{'[Questions]'}{'Q' . $question_index . '_GROUP_ID'} . '>' . $form_configuration{'[Questions]'}{'Q' . $form_configuration{'[Questions]'}{'Q' . $question_index . '_GROUP_ID'} . '_NAME'} . ': ' . $form_configuration{'[Questions]'}{'Q' . $question_index . '_TEXT'} . '</A></FONT></LI>',$form_configuration{'[Questions]'}{'Q' . $question_index . '_GROUP_ID'},$data{'PAGE_KEY'}));

			return(0);
		}
		#check for max length problems
		elsif($select_count > 0)
		{
			if(($select_count > $form_configuration{'[Questions]'}{'Q' . $question_index . '_MAX_RESPONSE'}) && ($form_configuration{'[Questions]'}{'Q' . $last_index . '_MAX_RESPONSE'} > 0))
			{
				#add the filled in values to the uid file (for fill in forms)
				%form_uid = &append_hash(\%form_uid,$data{'PAGE_KEY'},\%data);
				
				#write out the uid file
				&write_config(\%form_uid,$uid_file,1);

				#if dealing with a text field use the MAX LENGTH value else use MAX RESPONSE
				if($question_type eq 'TEXT')
				{
					#redisplay the page with the error message on it
					&display_html(&reload_form_replacement($reload_location,$form_configuration{'[Questions]'}{'Q' . $question_index . '_MAXLEN_ERR'} . '<BR><LI><FONT NAME="ARIAL,VERDANA,HELVETICA" SIZE="2"><A HREF=#Q' . $form_configuration{'[Questions]'}{'Q' . $question_index . '_GROUP_ID'} . '>' . $form_configuration{'[Questions]'}{'Q' . $form_configuration{'[Questions]'}{'Q' . $question_index . '_GROUP_ID'} . '_NAME'} . ': ' . $form_configuration{'[Questions]'}{'Q' . $question_index . '_TEXT'} . '</A></FONT></LI>',$form_configuration{'[Questions]'}{'Q' . $question_index . '_GROUP_ID'},$data{'PAGE_KEY'}));
				}
				else
				{
					#redisplay the page with the error message on it
					&display_html(&reload_form_replacement($reload_location,$form_configuration{'[Questions]'}{'Q' . $question_index . '_MAXRESPONSE_ERR'} . '<BR><LI><FONT NAME="ARIAL,VERDANA,HELVETICA" SIZE="2"><A HREF=#Q' . $form_configuration{'[Questions]'}{'Q' . $question_index . '_GROUP_ID'} . '>' . $form_configuration{'[Questions]'}{'Q' . $form_configuration{'[Questions]'}{'Q' . $question_index . '_GROUP_ID'} . '_NAME'} . ': ' . $form_configuration{'[Questions]'}{'Q' . $question_index . '_TEXT'} . '</A></FONT></LI>',$form_configuration{'[Questions]'}{'Q' . $question_index . '_GROUP_ID'},$data{'PAGE_KEY'}));
				}
				return(0);
			}
		}
	}	
	return(1);
}

########################################################################################
# 	FUNCTION THAT DISPLAYS THE BUILT ERROR PAGE 									   #
#	USE: &display_built_error($HTML_FILE,$ERROR_MSG,$ERR_NUM,$line_num);   			   #		
########################################################################################
sub display_built_error
{
	my $html_file = $_[0];
	my $error_msg = $_[1];
	my $error_num = $_[2];
	my $line_num = $_[3];
	my @source_lines = ();
	my $all_lines = "";
	my $err_replace = "";

	#open the source file and set the source file handle
	open (SRC_FILE, $html_file) || die &show_server_error($ERROR_NUM_FILE_ACCESS,"File Access Error",$form_configuration{'[MISC]'}{'FileAccessError'} . " [" . $html_file . "]", __LINE__);

	#store the whole source file in an array
	@source_lines = <SRC_FILE>;
	
	#now store the whole array into a single scalar
	$all_lines = "@source_lines";

	#insert the uid into our form '@*()'
	if($session_uid ne '')
	{
		$all_lines =~ s/\@\*\(uid\)/\&UID\=$session_uid/g;
	}
	else
	{
		$all_lines =~ s/\@\*\(uid\)//g;
	}

	#insert the uid into our form '@*()'
	if(exists $form_configuration{'[MISC]'}{'FormName'})
	{
		$all_lines =~ s/\@\*\(form_query\)/\?FORM\=$form_configuration{'[MISC]'}{'FormName'}/g;
	}
	else
	{
		$all_lines =~ s/\@\*\(form_query\)//g;
	}

	#insert the image server script into form '@*()'
	$all_lines =~ s/\@\*\(img\)/$form_directories{'[Defaults]'}{'ImageScript'}/g;

	#insert the data script into form '@*()'
	$all_lines =~ s/\@\*\(data\)/$data_script_location/g;
	
	$err_replace = "<B>Module:</B> RWS3<BR><B>Line:</B> " . $line_num . "<BR><B>Error #:</B> " . $error_num . "<BR><B>Details:</B> " . $error_msg;

	#insert the error message '@*()'
	$all_lines =~ s/\@\*\(ERROR_TEXT\)/$err_replace/g;

	&display_html($all_lines);
	return(1);
}

########################################################################################
# 	FUNCTION THAT REMOVES OLD UID FILES 		 									   #
#	USE: &remove_old_uid_files();							       	       			   #		
########################################################################################
sub remove_old_uid_files
{
	my $num_days = 0;
	my $dir_file = "";
	my @dir_files = ();
	my $full_file_path = "";
	my $uid_ext = "uid";

	#open the form directory
	if (opendir (FORMDIR, $form_directories{'[Forms]'}{$form_configuration{'[MISC]'}{'FormName'}}))
	{
		#store the files in a hash and close the directory
		@dir_files = readdir (FORMDIR);
		closedir FORMDIR;

		#loop thru all the files in the directory
		foreach $dir_file (sort @dir_files)
		{
			#make sure we are looking at a file and NOT a directory
			if (!(-d $dir_file))
			{
				$full_file_path	= &return_full_path($form_directories{'[Forms]'}{$form_configuration{'[MISC]'}{'FormName'}},$dir_file);

				#make sure the file exists (it should)
				if (-e $full_file_path)
				{
					if (lc($dir_file) =~ /^.+\.($uid_ext)$/)
					{
						$num_days = -M $full_file_path;

						if ($num_days > $form_configuration{'[MISC]'}{'UIDExpiration'}) 
						{
							unlink $full_file_path;
						}
					}
				}
			}
		}
	}
	return(1);
}

########################################################################################
# 	FUNCTION THAT ADDS RECORDS TO THE DATA FILE	 									   #
#	USE: $add_success=&add_data_records(); 				       	       			   	   #		
########################################################################################
sub add_data_records
{
	my $data_file = "";
	my $key_index = "";
	my $lock_file = "";
	my $key = "";
	my $value = "";
	my $ques = "";
	my %merge_hash = ();
	my %data_hash = ();
	my $counter = 0;
	my $lock_cnt = 0;
	my $data_line = "";
	my $month = "";
	my $yr = "";
	my $hour = "";
	my $append = "AM";
	my $prefix = "";
	my @visited_pages = ();
	my $tmp_key = "";
	my $tmp_index = "";

	#get the data file name
	$data_file = &return_full_path($form_directories{'[Forms]'}{$form_configuration{'[MISC]'}{'FormName'}},$form_configuration{'[MISC]'}{'DataFile'});
	$lock_file = $data_file . '.lck';
	$data_file .= '.rwd';

	#if lock file exists, delay up to 5 seconds before opening the data file
	while ((-e $lock_file) and ($lock_cnt < 5)) 
	{
		sleep 1;
		$lock_cnt++;
	}

	#if the lock file does not exist, create it
	if (!(-e $lock_file))
	{
		if (open (LOCK_FILE, ">$lock_file")) 
		{
			close(LOCK_FILE);
		}
	}
	
	#open the data file - IF OPEN FAILS KILL LOCK FILE TOO
	if(!(open(DATADIR, ">>$data_file")))
	{
		&show_server_error($ERROR_NUM_FILE_ACCESS,"File Access Error",$form_configuration{'[MISC]'}{'FileAccessError'} . " [" . $data_file . "]", __LINE__);
		#clean up the lock file if it exists
		if(-e $lock_file)
		{
			unlink $lock_file; 
		}
		return 0;
	}
			
	#loop thru all submitted items - skip MISC section
	foreach $key_index (sort keys %form_uid)
	{ 
		if($key_index ne '[MISC]')
		{
			foreach $key (sort keys %{$form_uid{$key_index}})
			{ 
				#turns '[Page_X]' into X]
				$tmp_index = (split(/\_/,$key_index))[1];

				#turns 'X]' into X
				$tmp_index = (split(/\]/,$tmp_index))[0];

				#do NOT write out info for pages that were NOT truly submitted (BACK BUTTON WAS USED)
				@visited_pages = split(/\,/,$form_uid{'[MISC]'}{'SubmittedPages'});
				foreach $tmp_key (@visited_pages)
				{
					if($tmp_key eq $tmp_index)
					{
						#add all page items into ONE HASH
						$merge_hash{$key} = $form_uid{$key_index}{$key};

						last;
					} 	
				} 		
			}
		}
	}
	
	#add the password entry if protected
	if($form_configuration{'[MISC]'}{'PasswordRequired'} eq '1')
 	{
		$data_hash{'Q0001'} = $form_uid{'[MISC]'}{'ID'};
 	}

	#loop thru the MERGED hash storing the data hash of key=value
	foreach $key_index (sort keys %merge_hash)
	{
		#converts QX_RWS_XXXX to QX
		$ques = (split(/\_/,$key_index))[0];		
		
		#store the correct answer, if checkbox use part of the KEY not value (on)!
		if($merge_hash{$key_index} eq 'on')
		{
			$value = (split(/\_/,$key_index,2))[1]; 
		}
		else
		{
			$value = $merge_hash{$key_index};
		}

		#replace CRLF with a space
		$value =~ s/\r\l/ /g;

		#add the value to the hash 
		if(!(exists $data_hash{$ques}))	
		{
			$data_hash{$ques} = $value;	
		}
		else
		{
			#if there are parentheses, remove them temporarily
			if (($data_hash{$ques} =~ /^\(/) && ($data_hash{$ques} =~ /\)$/))
			{
				$data_hash{$ques} = substr($data_hash{$ques},1,length($data_hash{$ques})-2);
			}
			$data_hash{$ques} .= "," . $value;
			$data_hash{$ques} = "(" . $data_hash{$ques} . ")";
		}
	}

	#loop thru the data hash and write the data
	for ($counter=1; $counter<=$form_configuration{'[MISC]'}{'NumQuestions'}; $counter++)
	{
		$prefix = sprintf("%04d",$counter);
		if($data_hash{'Q' . $prefix} ne '')
		{
			$data_line .= 'Q' . $prefix . '=' . $data_hash{'Q' . $prefix} . "\t"; 		
		}
	}
	
	#add the UID value
	$data_line .= 'UID=' . $session_uid . "\t";

	#add the time value
	$data_line .= 'IP=' . $ENV{'REMOTE_ADDR'} . "\t";

	#add the time value
	$data_line .= 'TIME=' . &get_time . "\t";

	#add the date value
	$data_line .= 'DATE=' . &get_date;

	#if password protected, increment the password count
	if($form_configuration{'[MISC]'}{'PasswordRequired'} eq '1')
	{
		#if valid password fails close data file w/o print and delete lock file
		if(&password_status($form_hash_file,$form_uid{'[MISC]'}{'ID'},1) == 0)
		{
			close (DATADIR);
			if(-e $lock_file)
			{
				unlink $lock_file; 
			}
			return 0;
		}
		#valid password
		else
		{
			#write out the data to the file
			print DATADIR "$data_line\n";
											
			if(!(close (DATADIR)))
			{
				if(-e $lock_file)
				{
					unlink $lock_file; 
				}
				&show_server_error($ERROR_NUM_FILE_ACCESS,"File Access Error",$form_configuration{'[MISC]'}{'FileAccessError'} . " [" . $data_file . "]", __LINE__);
				return 0;
			}
		}
	}
	#passwords are not required
	else
	{
		#write out the data to the file
		print DATADIR "$data_line\n";

		if(!(close (DATADIR)))
		{
			if(-e $lock_file)
			{
				unlink $lock_file; 
			}
			return 0;
		}
	}

	#clean up the lock file if it exists
	if(-e $lock_file)
	{
		unlink $lock_file; 
	}

	#set the file permissions
	chmod(0600, $data_file);

	return(1);
}

########################################################################################
# 	FUNCTION THAT ADDS RECORDS TO THE LOG FILE	 									   #
#	USE: &write_log($description,$access);				       	       			   	   #		
########################################################################################
sub add_log_record
{
	my $type = $_[0];
	my $access = $_[1];
	my $log_file = "";
	my $location = "";
	my $date = &get_date;
	my $time = &get_time;

	if($form_directories{'[Defaults]'}{'Logging'} eq '1')
	{
		#get the log file name
		$log_file = $form_configuration{'[MISC]'}{'LogFile'};
		if ($log_file eq '')
		{
			$log_file = 'log-file';
		}
		$log_file .= '.log';

		#get the full location
		$location = &return_full_path($form_directories{'[Forms]'}{$form_configuration{'[MISC]'}{'FormName'}},$log_file);

		#open the log file for appending
		open (LOG_FILE, ">>$location") || return(0);
		print LOG_FILE "$session_uid\t$type\t$access\t$form_uid{'[MISC]'}{'ID'}\t$ENV{'REMOTE_ADDR'}\t$date\t$time\n";
		close (LOG_FILE);
	}

	#set the file permissions
	chmod(0600, $location);

	return(1);
}

########################################################################################
# 	FUNCTION THAT ADDS CONFIRMATION DATA TO THE HMTL FILE							   #
#	USE: $data = &add_confirmation_data(confirm_html,$show_hidden,$convert_chars);	   #		
########################################################################################
sub add_confirmation_data
{  
	my $confirm_html = $_[0];
	my $show_hidden = $_[1];
	my $convert_chars = $_[2];
	my $completed_data = "";
	my $key = "";
	my $sub_key = "";
	my $tmp_key = "";
	my $ques_text = "";
	my $ans_text = "";
	my $tmp_var = "";
	my $question_index = "";
	my $lines = "";
	my $previous_ques = "";
	my %ordered_arr = ();
	my @visited_pages = ();
	my $ok = 0;
	my $tmp_index = "";
	my %missing = ();
	my $lcv = 0;

	@visited_pages = split(/\,/,$form_uid{'[MISC]'}{'SubmittedPages'});

	#order the array first
	foreach $key (sort keys %form_uid)
	{
		#skip over the MISC section and any complete pages (should not exist)
		if(($key ne '[MISC]') && ($key !~ /complete/))
		{
			#reset the flag
			$ok = 0;

			#turns '[Page_X]' into X]
			$tmp_index = (split(/\_/,$key))[1];

			#turns 'X]' into X
			$tmp_index = (split(/\]/,$tmp_index))[0];

			#determine if current page was a TRULY SUBMITTED PAGE
			foreach $tmp_key (@visited_pages)
			{
				if($tmp_key eq $tmp_index)
				{
					$ok = 1;
					last;
				} 	
			}

			#do NOT write out info for pages that were NOT truly submitted (BACK BUTTON WAS USED)
			if ($ok == 1)
			{
				#reset the missing array
				%missing = ();

				#loop thru each question in array{page_X}
				foreach $sub_key (sort keys %{$form_uid{$key}})
				{
					#if the $key starts with a 'Q' and is not the start or end variable	and is NOT hidden
		   			if($show_hidden == 1)
					{
		   				next if(($sub_key !~ /^Q/) || ($sub_key eq "QUESTION_START") || ($sub_key eq "QUESTION_END"));
					}
					else
					{
						next if(($sub_key !~ /^Q/) || ($sub_key eq "QUESTION_START") || ($sub_key eq "QUESTION_END") || ($sub_key =~ "RWS_HIDDEN"));
					}
					#set our new array to Q000X = Y
					$ordered_arr{$sub_key} = $form_uid{$key}{$sub_key};
					
					#grab the question number - turns 'QXXXX_XYZ=123' into QXXXX
					$tmp_var = (split(/\_/,$sub_key))[0];
					
					#set the question to located in our array
					$missing{$tmp_var} = 1; 
				}

				#check for missing items on the page from the start question to the end question
				for ($lcv = $form_uid{$key}{"QUESTION_START"}; $lcv <= $form_uid{$key}{"QUESTION_END"}; $lcv++)
				{
					#set the key = to QXXXX
					$tmp_key = "Q" . sprintf("%04d",$lcv);
					
					if($show_hidden != 1)
					{
						next if (defined $form_uid{$key}{$tmp_key . "_RWS_HIDDEN"});
					}
					
					#if this item is missing then add it to our array and set it as found
					if($missing{$tmp_key} != 1)
					{
						$ordered_arr{$tmp_key} = "";
						$missing{$tmp_key} = 1;
					}
				}
			}
		}
	}

	#loop thru just a list of questions
	foreach $key (sort keys %ordered_arr)
	{		
		#grab the question number - turns 'QX_XYZ=123' into QX
		$tmp_var = (split(/\_/,$key))[0];

		#turns 'QX' into X
		$question_index = substr($tmp_var,1);

		#if we have a multiple answer, add a comma to the current answer
		if($previous_ques eq $question_index)
		{
			$ans_text .= ",";
		}
		else
		{
			$previous_ques = $question_index;

   		 	if ($convert_chars == 1)
			{
			
   		 		#escape bad chars
				$ques_text =~ s/([^\w\s])/'&#'.ord($1).';'/ge;
				$ans_text =~ s/([^\w\s])/'&#'.ord($1).';'/ge;
			}

			#write out lines with the multiple answers now,replace the holders with the true values
			$lines =~ s/\@\*\(QUESTION_TEXT\)/$ques_text/g;
			$lines =~ s/\@\*\(ANSWER_TEXT\)/$ans_text/g;

			#reset the answer text
			$ans_text = "";

			#reset lines to the replacement html
			$lines .= $confirm_html . "\n";
		}
 
		#store the question text
		$ques_text = $form_configuration{'[Questions]'}{'Q' . $question_index . '_TEXT'};

		if($ques_text eq '')
		{
			$ques_text = $MISSING_QUESTION_TEXT;	
		}
		if($ordered_arr{$key} eq '')
		{
			$ans_text = $MISSING_ANSWERS;	
		}
		elsif($ordered_arr{$key} eq 'on')
		{
			$ans_text .= (split(/\_/,$key,2))[1]; 
		}
		else
		{
			$ans_text .= $ordered_arr{$key};
		}
	}

	#if we have a multiple answer, add a comma to the current answer
	if($previous_ques eq $question_index)
	{
		#escape bad chars 
		if ($convert_chars == 1)
		{
			$ques_text =~ s/([^\w\s])/'&#'.ord($1).';'/ge;
			$ans_text =~ s/([^\w\s])/'&#'.ord($1).';'/ge;
		}

		#replace the holders with the true values
		$lines =~ s/\@\*\(QUESTION_TEXT\)/$ques_text/g;
		$lines =~ s/\@\*\(ANSWER_TEXT\)/$ans_text/g;
	}					

	return $lines;
}

########################################################################################
# 	FUNCTION THAT RETURNS A RANDOM PAGE TO DISPLAY									   #
#	USE: $rand_page = &next_random_page($random_group_id);       	   #		
########################################################################################
sub next_random_page
{
	my $random_group = $_[0];
	my @pages = ();
	my @random_group_pages = ();
 	my $index = 0;
	my $error = 0;
	my $length = 0;
	my $sub_length = 0;
	my $key = "";
	my $sub_key = "";
	my $new_key = "";
	my $found = 0;
	my @available_pages = ();
	my $largest_page = 0;

	#store the submitted pages in a hash
	@pages = split(/\,/,$form_uid{'[MISC]'}{'SubmittedPages'});
	
	#store the random group pages for the current group in a hash
	@random_group_pages = split(/\,/,$form_configuration{'[MISC]'}{'RandomGroup' . $random_group});

	#get the length of the list
   	$length = @random_group_pages;

	#make sure there are available pages from the group that have not been submitted
	foreach $key (@random_group_pages)
	{
		#store the largest page index in the group
		if($key > $largest_page)
		{
			$largest_page = $key;	
		}

		#reset the found flag
 		$found = 0;
 		foreach $sub_key (@pages)
 		{
 			#if random page was already submitted, increment the count 
 			if($sub_key == $key)
 			{
 				$found = 1;
 			}
 		}
 
 		#add the page index to the available pages hash
 		if($found == 0)
 		{
 			push (@available_pages,$key);
 		}
	}

	#store the number of available pages
	$sub_length = @available_pages;
 		
	#if all the random pages have been submitted return the next page in sequence
	if($sub_length <= 0)
	{	
		return(&next_page_key($largest_page));
	}
	
	#generates random seed
	srand;

	#get a random index from the random group pages
	$index = rand @available_pages;

	return ('[page_' . $available_pages[$index] . ']'); 
}

########################################################################################
# 	FUNCTION THAT RETURNS THE NEXT KEY												   #
#	USE: $page_key = &next_page_key($current_index);								   #		
########################################################################################
sub next_page_key
{
	my $current_index = $_[0];
	my $new_key = "";
	my $location = "";

	#increment the current index
	$current_index++;

	#try the next page in sequence
	$new_key = '[page_' . $current_index . ']';
		 
	#if there are no more pages in the sequence, load the confirmation page or 1st success page 
	if(!(exists $form_configuration{$new_key}))	
	{
		#try to locate a confirmation page
		$location = &return_full_path($form_directories{'[Forms]'}{$form_configuration{'[MISC]'}{'FormName'}},"confirmation_page.html");
		if(-e $location)
		{
			return("[confirmation_page]");
		}

		#no confirmation page, try to locate a complete form page in the sequence
		$new_key = '[complete_page_' . $current_index . ']';
		if(!(exists $form_configuration{$new_key}))	
		{
			if($form_configuration{'[MISC]'}{'FirstCompletePage'} =~ /^http/)
			{
				#return the URL if a success URL was designated
				return($form_configuration{'[MISC]'}{'FirstCompletePage'});
			}
			else
			{
				#make sure the complete page exists
				if(!(exists $form_configuration{'[complete_page_' . $form_configuration{'[MISC]'}{'FirstCompletePage'} . ']'}))	
				{
   					&general_error_screen('Form Branch Error','<B>Module:</B> RWS3<BR><B>Line:</B> ' . __LINE__ . '<BR><B>Details:</B> The designated branch path is invalid. Please contact the form administrator before continuing.',$form_configuration{'[MISC]'}{'AdminAddress'});
					exit;
				}
				else
				{
					#return the page key of the first complete page
					return('[complete_page_' . $form_configuration{'[MISC]'}{'FirstCompletePage'} . ']');
				}
			}
		}	
	}
	#return the next page in the sequence
	return ($new_key); 
}

########################################################################################
# 	FUNCTION THAT PRODUCES A SERVER ERROR											   #
#	USE: &show_server_error($err_num,$err_title,$err_text,$line);					   #		
########################################################################################
sub show_server_error
{
	my $err_num = $_[0];
	my $err_title = $_[1];
	my $err_text = $_[2];
	my $err_line = $_[3];
	my $error_file = "";

	#get the location of the potential error page
	$error_file = &return_full_path($form_directories{'[Forms]'}{$form_configuration{'[MISC]'}{'FormName'}},'error_page.html');
	
	#if the error page exists then display the designer-built page		
	if(-e $error_file)
	{
		&display_built_error($error_file,$err_text,$err_num,$err_line);
	}
	else
	{
		&general_error_screen($err_title,"<B>Module:</B> RWS3<BR><B>Line:</B> " . $err_line . "<BR><B>Error #:</B> " . $err_num . "<BR><B>Details:</B> " . $err_text,$form_configuration{'[MISC]'}{'AdminAddress'});
	}
}

########################################################################################
# 	FUNCTION THAT RETURNS THE BODY FOR A SUBMISSION EMAIL  		       				   #	
#	USE: $email_body=&construct_email_body();					       	       		   #		
########################################################################################
sub construct_email_body
{
	my $header = "";
	my $date = "";
	my $day = (Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday)[(localtime)[6]];
	my $mday = (localtime)[3];
	my $month = (January,February,March,April,May,June,July,August,September,October,November,December)[(localtime)[4]]; 
	my $yr = (localtime)[5]+1900;
	my $html_content = "";

	$date = $day . ", " . $month . " " . $mday . ", " . $yr;    

	$header .= "================================================================\n";
	$header .= " *** Automated Mailing - Remark Web Survey 3.0 *** \n";
	$header .= "================================================================\n\n";

	$header .= "Form:\t[" . $form_configuration{'[MISC]'}{'FormName'} . "]\n";
	$header .= "URL:\t" . $form_configuration{'[MISC]'}{'DataScript'} . "?form=" . $form_configuration{'[MISC]'}{'FormName'} . "\n";
	$header .= "Date:\t" . $date . "\n";
	$header .= "Time:\t" . &get_time() . "\n\n\n";

	$html_content = "@*(QUESTION_TEXT)\n";
	$html_content .= "   --> @*(ANSWER_TEXT)\n";

	$header .= &add_confirmation_data($html_content,1,0);

	return $header;
}

########################################################################################
# 	FUNCTION THAT RETURNS A HASH OF ALL SUBMITTED DATA  		       				   #	
#	USE: %data=&merge_submitted_data();					       	       		   		   #		
########################################################################################
sub merge_submitted_data
{
	my $key_index = ""; ;
	my $tmp_index = "";
	my $tmp_key = "";
	my %merge_hash = ();
	my @visited_pages = ();
	my $key = "";
	
 	#loop thru all submitted items - skip MISC section
	foreach $key_index (sort keys %form_uid)
	{ 
		next if(($key_index eq '[MISC]') || ($key_index eq 'x') || ($key_index eq 'y'));
		
		foreach $key (sort keys %{$form_uid{$key_index}})
		{ 
			next if(($key eq 'QUESTION_START') || ($key eq 'QUESTION_END') || ($key !~ /^Q/));

			#turns '[Page_X]' into X]
			$tmp_index = (split(/\_/,$key_index))[1];

			#turns 'X]' into X
			$tmp_index = (split(/\]/,$tmp_index))[0];

			#do NOT write out info for pages that were NOT truly submitted (BACK BUTTON WAS USED)
			@visited_pages = split(/\,/,$form_uid{'[MISC]'}{'SubmittedPages'});
			foreach $tmp_key (@visited_pages)
			{
				if($tmp_key eq $tmp_index)
				{
					#add all page items into ONE HASH
					$merge_hash{$key} = $form_uid{$key_index}{$key};

					last;
				} 	
			} 		
		}
	}

	return (%merge_hash);
}

########################################################################################
# 	FUNCTION THAT LOADS THE FIRST PAGE IN A SEQUENCE     		       				   #	
#	USE: &load_first_page();					       	       		   		           #		
########################################################################################
sub load_first_page
{
	my $tmp_page = "";
	my $target_page = "";
	my %merged_data = ();
		
	if(defined $form_configuration{'[page_1]'}{'#RANDOM_ID#'})
	{
		if($form_configuration{'[page_1]'}{'#RANDOM_ID#'} ne '-1')
		{
			$tmp_page = &next_random_page($form_configuration{'[page_1]'}{'#RANDOM_ID#'});

			#if a URL was specified (SHOULD NOT be the case) goto that page instead
			if($tmp_page =~ /^http/)
			{
				%merged_data = &merge_submitted_data();
				&browser_redirect($tmp_page,$form_directories{'[Defaults]'}{'CGIRedirect'},\%merged_data);  
			}
			else
			{
				#get the target file from the target hash
				$target_page = $form_configuration{$tmp_page}{"#SRC#"};

				#if a URL was specified goto that page instead
				if($target_page =~ /^http/)
				{
					%merged_data = &merge_submitted_data();
					&browser_redirect($target_page,$form_directories{'[Defaults]'}{'CGIRedirect'},\%merged_data);   
				}
				else
				{
					#concatenate the form's directory with the target page
					$target_page = &return_full_path($form_directories{'[Forms]'}{$form_configuration{'[MISC]'}{'FormName'}},$target_page);	
						
					#navigate to the appropriate page
					&display_html(&reload_form_replacement($target_page,'','',$tmp_page));
				}
			}
		}
		else
		{
			&display_html(&reload_form_replacement(&get_next_page,'','','[page_1]'));
		}
	}
	else
	{
		&display_html(&reload_form_replacement(&get_next_page,'','','[page_1]'));
	}

	#add log record
	&add_log_record('form access','permitted');
	
	exit;
}