#!/usr/local/bin/perl

# Name: database_manager.cgi
#
# Version: 2.0
#
# Last Modified: 5-14-96
#
# Copyright Information: This script was written by Selena Sol
#     (selena@eff.org, http://www.eff.org/~erict) having been inspired by
#     countless other perl authors.  Feel free to copy, cite, reference,
#     sample, borrow or plagiarize the contents.  However, if you
#     don't mind, please let me know where it goes so that I can at least
#     watch and take part in the development of the memes. Information
#     wants to be free, support public domain freware.
#
# Description: This database manager script allows a database
#     administrator (or anyone who has been given password verified
#     access) to manipulate a flatfile UNIX database.  The db admin can
#     add to, modify and delete from the database using a web-based
#     interface. Further, the script supports multiple admins because it
#     incorporates lock file routines so that no-one can actually
#     manipulate the data file while someone else is manipulating it.
#
# Installation: See db_manager.setup

# First, print out the HTTP header.  We'll output this quickly so that we 
# will be able to do some of our debugging from the web and so that in 
# the case of a bogged down server, we won't get timed-out.

###########################################################################
#                       Print http Header.                                #
###########################################################################

  print "Content-type: text/html\n\n";

###########################################################################
#                       Require Libraries.                                #
###########################################################################

  unshift (@INC, "$lib");

# Now require the necessary files with the subroutine at the end of this 
# script marked by "sub require".  We use this subroutine so that if 
# there is a problem with the require, we will get a meaningful error 
# message.

  $lib = "Library";
  &require("$lib/cgi-lib.pl", "$lib/cgi-lib.sol",
 	   "$lib/auth-lib.pl");

# Now use cgi-lib.pl to parse the incomming form data.  We'll pass 
# cgi-lib.pl (*form_data) so that our variable will come out as 
# $form_data{'key'} instead of $in{'$key'}.  I like to use form_data 
# because it is easier for me to remember what the variable is.

###########################################################################
#                        Gather Form Data.                                #
###########################################################################

  &ReadParse(*form_data);
  if ($form_data{'database'} ne "")
    {
    $setup_file = $form_data{'database'};
    }
  else
    {
    $setup_file = "db_manager.setup";
    }
  &require("Databases/$setup_file");

#######################################################################
#                       Basic User Authentication                     #
#######################################################################

# Now let's check to see if the client is a user who is authorized to use
# this script.  We will use the web of routines in the library
# file session-lib.pl to do the following:
#
# 1. Ask the user to submit a userid and password.
# 2. Check that userid/password pair against the information in
#    $user_file.
# 3. If the information is invalid, dissallow enterence and provide a
#    routine for the user to apply for an account.
# 4. If the information was valid, send back to this script a "session
#    file id" corresponding to a session file which will have been created
#    by session-lib.pl and which will contain the users personal
#    information.  This script will then pass along the session id as a
#    hidden variable throught in order to make sure that the user is
#    valid.

# We'll pass the subroutine GetSessionInfo which is contained in
# auth-lib.pl three parameters, the $session_file value (which will be
# nothing if one has not been set yet), the name of this script (so it can
# provide links back) and the associative array of form data we got from
# cgi-lib.pl.

  if ($form_data{'session_file'} ne "")
      {
      $session_file = $form_data{'session_file'};
      }

($session_file, $session_username, $session_group, $session_first_name,
        $session_last_name, $session_email) =
&GetSessionInfo($session_file, $database_manager_script_url, *form_data);

  @group_array = split (/:/, $session_group);

# Take off the newline character for the last member in the array.

  chop $session_email;

###########################################################################
#                       Print out Frontpage.                              #
###########################################################################

# At this point, we have passsed through security. So let's find out what
# the client wants.  First, check to see if this person needs the very
# first page.  We know that the client needs to see the firstpage if she
# has clicked on a input button named return_to_frontpage or if she has
# clicked on the "Login" button. The || means "or".  

  if ($form_data{'return_to_frontpage'} ne "" || 
      $form_data{'session_file'} eq "")
    {

# Okay, so if we got to this line, it means that their session file was
# valid.  So let's print out the database manager frontpage which will
# give the client her choices of actions (add, modify, delete, and view).

    print <<"    end_of_html";
    <HTML><HEAD><TITLE>Database Manager Frontpage</TITLE></HEAD>
    <BODY>
    <CENTER><H2>Database Manager Frontpage</H2></CENTER>
    <BLOCKQUOTE>
    Thanks for checking out these scripts.  They are my
    most advanced to date.  Feel free to try them out here and perhaps
    read through the code in another window.  However, I ask only that you
    please clean up after yourself so that the database doesn't get too
    unweildly. Try this...1) add an item, 2) modify that item, and 3)
    delete that item.  Thanks
    </BLOCKQUOTE>
    <FORM METHOD = "post" ACTION = "$database_manager_script_url">
    <CENTER>
    <INPUT TYPE = "hidden" NAME = "database" VALUE = "$setup_file">
    <INPUT TYPE = "hidden" NAME = "session_file" VALUE = "$session_file">    
    <INPUT TYPE = "submit" NAME = "add_form" VALUE = "Add an Item">    
    <INPUT TYPE = "submit" NAME = "search_form_delete" 
	   VALUE = "Delete an Item">  
    <INPUT TYPE = "submit" NAME = "search_form_modify" 
	   VALUE = "Modify an Item">
    <INPUT TYPE = "submit" NAME = "search_form_view" 
	   VALUE = "View the Database">
    end_of_html
    exit;
    }

###########################################################################
#                      Print out Add Item Form.                           #
###########################################################################

# Now let's check to see if the client was actually asking us for the 
# form to add an entry to the database

  if ($form_data{'add_form'} ne "")
    {

# Print out the page header, body, document header, and form tags
# as we did for the Frontpage.

    print <<"    end_of_html";
    <HTML><HEAD><TITLE>Adding an Item to the Database</TITLE></HEAD>
    <BODY>
    <CENTER><H2>Adding an Item to the Database</H2></CENTER>
    <FORM METHOD = "post" ACTION = "$database_manager_script_url">
    <CENTER>
    end_of_html

# Now create the input form using the subroutine create_input_form at the
# end of this script.  This subroutine will simply create an input field
# for each of the fields in the database and present it in table format.

    &create_input_form;

# Now print out the page footers as we did for the frontpage.

    print <<"    end_of_html";
    </TABLE><CENTER><P>
    <INPUT TYPE = "hidden" NAME = "database" VALUE = "$setup_file">
    <INPUT TYPE = "hidden" NAME = "session_file" 
	   VALUE = "$form_data{'session_file'}">
    <INPUT TYPE = "submit" NAME = "submit_addition"
	   VALUE = "Submit Addition">
    <INPUT TYPE = "submit" NAME = "return_to_frontpage"
	   VALUE = "Return to Frontpage">
    </CENTER></FORM></BODY></HTML>
    end_of_html

    exit;
    }

###########################################################################
#                     Print out Search Form (Delete).                     #
###########################################################################

# If the client is asking to delete, let's send a form so that they can
# specify which database item they wanted deleted.

  if ($form_data{'search_form_delete'} ne "")
    {

# Before we can begin deleteing, we need to find out which item the client
# is interested in deleting.  In order to do that we need the client to
# give us some information (which item).  Likewise, we need to tell the
# client which items are available to delete (a database listing of
# possible items). However, we can't just begin barfing up all the items
# in our database...the browser will run out of memory, and do we really
# want the client to get all of the info in the database anyways! Instead,
# we will have the client give us one or more search terms so that we can
# put together a reasonably sized list from which the client can then
# choose.  

    print <<"    end_of_html";
    <HTML><HEAD><TITLE>Query Database for Deletion</TITLE></HEAD>
    <BODY>
    <CENTER><H2>Query Database for Deletion</H2></CENTER>
    <FORM METHOD = "post" ACTION = "$database_manager_script_url">
    <CENTER>
    end_of_html

# Now create the input form using the subroutine create_input_form at the
# end of this script.  (Same as the equivalent call for add, above)

    &create_input_form;

# Now add a form input for "exact match" and the form, body and html
# footers and tags. BTW, all searches are case insensitive, but the
# exact match will not match gen'eric' if the search is for eric whereas
# the non-exact search will.

    print <<"    end_of_html";
    <TH>Exact Match?</TH><TD>
    <INPUT TYPE = "checkbox" NAME = "exact_match">
    </TD></TR></TABLE><P>
    <INPUT TYPE = "hidden" NAME = "database" VALUE = "$setup_file">
    <INPUT TYPE = "hidden" NAME = "session_file" VALUE = "$form_data{'session_file'}">
    <INPUT TYPE = "submit" NAME = "search_database_delete"
	   VALUE = "Submit Search Term">
    <P><BLOCKQUOTE>To get a full view of database, submit \"no\"
    keywords.  But beware, if there are too many items in your database,
    you will exceede the memory of your browser.
    </CENTER></FORM></BODY></HTML>
    end_of_html
    exit;
    }

###########################################################################
#              Print out Search Results HTML Header (Delete).             #
###########################################################################

# Okay, now we need a routine to accept the cleint defined search term(s)
# and search the database, presenting a dynamically generated list of
# "hits" from which the client can then begin deleting.

  if ($form_data{'search_database_delete'} ne "")
    {

# Now conduct the search and print out the results.  

# First, we'll print out the page header using the same subroutine calls
# that we used above.

  print <<"  end_of_html";
  <HTML><HEAD><TITLE>Deleting an Item from the Database</TITLE></HEAD>
  <BODY>
  <CENTER><H2>Deleting an Item from the Database</H2></CENTER>
  <FORM METHOD = "post" ACTION = "$database_manager_script_url">
  <CENTER>
  end_of_html

###########################################################################
#                     Perform the Search (Delete)                         #
###########################################################################

# Now begin searching the database by using the subroutine
# search_database which can be found at the end of this script.  We'll
# pass the subroutine one parameter, "delete" so that the subroutine knows
# how to output the results of the search. 

  &search_database ("delete");

# Finally, print up a list of hits in a table format.  $search_results,
# returned from &search_database, contains all of the hits already in the
# form of table rows.  The client will then be able to choose which item
# to delete and actually delete it with the  
# "if ($form_data{'submit_deletion'} ne "")" routine below

  print "<TABLE BORDER = \"1\" CELLPADDING = \"4\" CELLSPACING = \"4\">";

  print &table_header ("Delete<BR>Item");
  push (@field_names, "Id");
  print &table_header (@field_names);
  print "</TR>\n";
  print "$search_results";
  print <<"  end_of_html";
  </TABLE><P>
  $search_notice<P>
  <INPUT TYPE = "hidden" NAME = "database" VALUE = "$setup_file">
  <INPUT TYPE = "hidden" NAME = "session_file"
         VALUE = "$form_data{'session_file'}">
  <INPUT TYPE = "submit" NAME = "submit_deletion"
         VALUE = "Submit Deletion">
  <INPUT TYPE = "submit" NAME = "return_to_frontpage"
         VALUE = "Return to Frontpage">
  </CENTER></FORM></BODY></HTML>
  end_of_html

  exit;
  }

###########################################################################
#                     Print out Search Form (Modify).                     #
###########################################################################

# Okay, now we need to do the same thing, but for modification.

  if ($form_data{'search_form_modify'} ne "")
    {

# Print up the familiar page header.

    print <<"    end_of_html";
    <HTML><HEAD><TITLE>Query Database for Modification</TITLE></HEAD>
    <BODY>
    <CENTER><H2>Query Database for Modification</H2></CENTER>
    <FORM METHOD = "post" ACTION = "$database_manager_script_url">
    <CENTER>
    end_of_html

# Now create the input form using the subroutine create_input_form at the
# end of this script.

    &create_input_form;

# Plop in the footer just as we did for delete above.

    print <<"    end_of_html";
    <TH>Exact Match?</TH><TD>
    <INPUT TYPE = "checkbox" NAME = "exact_match">
    </TD></TR></TABLE><P>
    <INPUT TYPE = "hidden" NAME = "database" VALUE = "$setup_file">
    <INPUT TYPE = "hidden" NAME = "session_file"
           VALUE = "$form_data{'session_file'}">
    <INPUT TYPE = "submit" NAME = "search_database_modify"
           VALUE = "Submit Search Term">
    <P><BLOCKQUOTE>To get a full view of database, submit \"no\"
    keywords.  But beware, if there are too many items in your database,
    you will exceede the memory of your browser.
    </CENTER></FORM></BODY></HTML>
    end_of_html
    exit;
    }

###########################################################################
#              Print out Search Results HTML Header (Modify).             #
###########################################################################

# Okay, just as we did for delete above, let's print out the results of
# the query for modification.

  if ($form_data{'search_database_modify'} ne "")
    {

# Now conduct the search and print out the results.  First, we'll print
# out the page header using the same subroutine calls that we used above.

  print <<"  end_of_html";
  <HTML><HEAD><TITLE>Modifying an Item in the Database</TITLE></HEAD>
  <BODY>
  <CENTER><H2>Modifying an Item in the Database</H2></CENTER>
  <FORM METHOD = "post" ACTION = "$database_manager_script_url">
  <CENTER>
  end_of_html

###########################################################################
#                     Perform the Search (Modify)                         #
###########################################################################

# Now begin searching the database using the subroutine search_database
# at the end of the script just as we did for delete. 

  &search_database ("modify");

# Now, print up a list of hits in a table format.  $search_results,
# returned from &search_database, contains all of the hits already in the
# form of table rows.

  print "<TABLE BORDER = \"1\" CELLPADDING = \"4\" CELLSPACING = \"4\">";
  print "<TH>Modify<BR>Item</TH>";

  push (@field_names, "Id");
  print &table_header (@field_names);

  print "</TR>\n";
  print "$search_results";
  print "</TABLE><P>";
  print "$search_notice<P>";

# Now print out the same form that we used for the Add an Item form with
# the subroutine &create_input_form below.  

# Thus, the client will be able to specify an item to modify in the table 
# above and then type in new information with which to update in the form 
# inputs below.

    &create_input_form;

# Print up the usual footer as well.

    print <<"    end_of_html";
    </TABLE><CENTER><P>
    <INPUT TYPE = "hidden" NAME = "database" VALUE = "$setup_file">
    <INPUT TYPE = "hidden" NAME = "session_file"
           VALUE = "$form_data{'session_file'}">
    <INPUT TYPE = "submit" NAME = "submit_modification"
           VALUE = "Submit Modification">
    <INPUT TYPE = "submit" NAME = "return_to_frontpage"
           VALUE = "Return to Frontpage">
    </CENTER></FORM></BODY></HTML>
    end_of_html
    exit;
    }

###########################################################################
#                     Print out Search Form (View).                       #
###########################################################################

# Okay, yet another similar routine, this time just to view the database.

  if ($form_data{'search_form_view'} ne "")
    {

# print out the usual header.

    print <<"    end_of_html";
    <HTML><HEAD><TITLE>Query Database for Viewing</TITLE></HEAD>
    <BODY>
    <CENTER><H2>Query Database for Viewing</H2></CENTER>
    <FORM METHOD = "post" ACTION = "$database_manager_script_url">
    <CENTER>
    end_of_html

# Now create the input form using the subroutine create_input_form at the
# end of this script.  This is all exactly the same as we've done above.

    &create_input_form;

    print <<"    end_of_html";
    <TH>Exact Match?</TH><TD>
    <INPUT TYPE = "checkbox" NAME = "exact_match">
    </TD></TR></TABLE><P>
    <INPUT TYPE = "hidden" NAME = "database" VALUE = "$setup_file">
    <INPUT TYPE = "hidden" NAME = "session_file"
           VALUE = "$form_data{'session_file'}">
    <INPUT TYPE = "submit" NAME = "search_database_view"
           VALUE = "Submit Search Term">
    <P><BLOCKQUOTE>To get a full view of database, submit \"no\"
    keywords.  But beware, if there are too many items in your database,
    you will exceede the memory of your browser.
    </CENTER></FORM></BODY></HTML>
    end_of_html
    exit;
    }

###########################################################################
#              Print out Search Results HTML Header (View).               #
###########################################################################

# Search the database for the client to view.  This is all exactly the
# same as we've done above.

  if ($form_data{'search_database_view'} ne "")
    {
    print <<"    end_of_html";
    <HTML><HEAD><TITLE>Viewing the Database</TITLE></HEAD>
    <BODY>
    <CENTER><H2>Viewing the Database</H2></CENTER>
    <FORM METHOD = "post" ACTION = "$database_manager_script_url">
    <CENTER>
    end_of_html

###########################################################################
#                     Perform the Search (View)                           #
###########################################################################

# Now begin searching the database.  But this time, send the subroutine a
# parameter of "none" because we do not want any radio buttons in the
# resulting table.  There will be no items to select since all the client
# wants to do is view the database.

  &search_database ("none");

# Finally, print up a list of hits in a table format.  

  print <<"  end_of_html";
  <TABLE BORDER = "1" CELLPADDING = "4" CELLSPACING = "4">
  end_of_html

  push (@field_names, "Id");
  print &table_header (@field_names);
  print "</TR>\n";
  print "$search_results";

  print <<"  end_of_html";
  </TABLE><CENTER><P>
  $search_notice<P>
  <INPUT TYPE = "hidden" NAME = "database" VALUE = "$setup_file">
  <INPUT TYPE = "hidden" NAME = "session_file"
         VALUE = "$form_data{'session_file'}">
  <INPUT TYPE = "submit" NAME = "add_form" VALUE = "Add an Item">
  <INPUT TYPE = "submit" NAME = "search_form_delete" 
	 VALUE = "Delete an Item">
  <INPUT TYPE = "submit" NAME = "search_form_modify" 
	 VALUE = "Modify an Item">
  <INPUT TYPE = "submit" NAME = "return_to_frontpage" 
	 VALUE = "Return to Frontpage">
  </CENTER></FORM></BODY></HTML>
  end_of_html
  exit;
  }

#############################################################################
#                      Adding to the Database                               #
#############################################################################

  if ($form_data{'submit_addition'} ne "")
    {

# In the case of an add, we'll have to assign the new database entry a 
# unique database ID number.  We'll do so by accessing the counter file 
# which keeps track of the last database id number used.  The counter 
# subroutine is located in cgi-lib.sol and will send us back a new 
# (incremented by one) number and then adjesut the counter file 
# appropriately.  The unique ID nmumber is essential for modifying the 
# database.  The coputer routine takes one parameter, the location of the
# counter file.

    &GetFileLock ("$lock_file");
    &counter($counter_file);
    &ReleaseFileLock ("$lock_file");

# Take the incoming form data and format it the way our database is set 
# up to understand (ie: delimited by | and ending with a new line).

    foreach $field (@field_names)
      {
      $value = "$FIELD_ARRAY{$field}";
      $form_data{$value} =~ s/\n/<BR>/g;
      $form_data{$value} =~ s/\r\r/<P>/g;
      $form_data{$value} =~ s/\|/~~/g;
      if ($form_data{$value} eq "")
        {
        $form_data{$value} = "<CENTER>-</CENTER>";
        }
      $new_row .= "$form_data{$value}|";
      }

    $new_row .= "$item_number";

# Now create a lockfile while we edit our database file.  The reason that
# we do this is so that if two people are trying to edit the datafile at
# one time, one person will not destroy the modifications made by the
# other person.  We'll create the lock file using the subroutine
# GetFileLoc in cgi-lib.sol, passing it one parameter, the location of
# the lock file used by this program.  You should definitely not create
# the lock file yourself...

    &GetFileLock ("$lock_file");
    open (DATABASE, ">>$data_file") || &open_error($data_file);
    print DATABASE "$new_row";
    print DATABASE "\n";
    close (DATABASE);

# Now close the $lock_file and delete it so that others may access the 
# data_file.

   &ReleaseFileLock ("$lock_file");

# Now display the contents of the database as we did in the View Database 
# option above.

    print <<"    end_of_html";
    <HTML><HEAD><TITLE>Item Added to the Database</TITLE></HEAD>
    <BODY>
    <CENTER><H2>Item Added to the Database</H2></CENTER>
    <FORM METHOD = "post" ACTION = "$database_manager_script_url">
    <CENTER>
    <INPUT TYPE = "hidden" NAME = "database" VALUE = "$setup_file">
    <INPUT TYPE = "hidden" NAME = "session_file"
           VALUE = "$form_data{'session_file'}">
    <INPUT TYPE = "submit" NAME = "add_form" VALUE = "Add an Item">
    <INPUT TYPE = "submit" NAME = "search_form_delete"
           VALUE = "Delete an Item">
    <INPUT TYPE = "submit" NAME = "search_form_modify"
           VALUE = "Modify an Item">
    <INPUT TYPE = "submit" NAME = "search_form_view"
           VALUE = "View the Database">
    </CENTER></FORM></BODY></HTML>
    end_of_html
    exit;
    }

#############################################################################
#                      Deleting from the Database                           #
#############################################################################

  if ($form_data{'submit_deletion'} ne "")
    {

    open (DATABASE, "$data_file") || &open_error($data_file);

    while (<DATABASE>)
      {
      if ($_ =~ /^COMMENT:/)
        {
        $new_data .= "$_";
        }
      else
        {
        @fields = split (/\|/, $_);
        $item_id = pop(@fields);
        unless ($item_id eq "$form_data{'delete'}")
          {              
          $new_data .= "$_";
          }
        }
      }
    close (DATABASE);

    &GetFileLock ("$lock_file");
    open (TEMPFILE, ">$temp_file") || &open_error($temp_file);
    print TEMPFILE "$new_data";
    close (TEMPFILE);
    rename ($temp_file, $data_file);
    &ReleaseFileLock ("$lock_file");

# Now print up the usual footer with an option to add another item.

    print <<"    end_of_html";
    <HTML><HEAD><TITLE>Your Item has been deleted</TITLE></HEAD>
    <BODY>
    <CENTER><H2>Your Item has been deleted</H2></CENTER>
    <FORM METHOD = "post" ACTION = "$database_manager_script_url">
    <CENTER>
    <INPUT TYPE = "hidden" NAME = "database" VALUE = "$setup_file">
    <INPUT TYPE = "hidden" NAME = "session_file"
           VALUE = "$form_data{'session_file'}">
    <INPUT TYPE = "submit" NAME = "add_form" VALUE = "Add an Item">
    <INPUT TYPE = "submit" NAME = "search_form_delete"
           VALUE = "Delete an Item">
    <INPUT TYPE = "submit" NAME = "search_form_modify"
           VALUE = "Modify an Item">
    <INPUT TYPE = "submit" NAME = "search_form_view"
           VALUE = "View the Database">
    </CENTER></FORM></BODY></HTML>
    end_of_html
    exit;
    }

#############################################################################
#                 Modifying an Item in the Database                         #
#############################################################################

  if ($form_data{'submit_modification'} ne "")
    {
    if ($form_data{'modify'} eq "")
      {
      print <<"      end_of_html";
      <HTML><HEAD><TITLE>Modifying an Item in the Database</TITLE></HEAD>
      <BODY>
      <CENTER><H2>Modifying an Item in the Database</H2></CENTER>
      <BLOCKQUOTE>
      I'm sorry, I was not able to modify the database because none of
      the radio buttons on the table was selected so I was not sure which
      item to modify.  Would you please make sure that you select an item
      \"and\" fill in the new information.  Please hit the back
      button and try again.  Thanks.
      </BLOCKQUOTE>
      end_of_html
      exit;
      }

    open (DATABASE, "$data_file") || &open_error($data_file);

    while (<DATABASE>)
      {
      if ($_ =~ /^COMMENT:/)
        {
        $new_data .= "$_";
        }

      else
        {
        @fields = split (/\|/, $_);
        $item_id = pop(@fields);
        push (@fields, $item_id);
 
        if ($item_id eq "$form_data{'modify'}")
          {
          @old_fields = @fields;
          }
        else
          {              
          $new_data .= "$_";
          }
        }
      }

    $counter = 0;
    $new_line = "";
    until ($counter >= @field_values)
      {
      $value = "";
      $value = "$field_values[$counter]";

      if ($form_data{$value} eq "")
        {
        $new_line .= "$old_fields[$counter]|";
        }
      else
        {
        $form_data{$value} =~ s/\n/<BR>/g;
        $form_data{$value} =~ s/\r\r/<P>/g;
        $form_data{$value} =~ s/\|/~~/g;
        if ($form_data{$value} eq "")
          {
          $form_data{$value} = "<CENTER>-</CENTER>";
          }
        $new_line .= "$form_data{$value}|";
        }
      $counter++;
      }
    chop $new_line;

    &GetFileLock ("$lock_file");
    open (TEMPFILE, ">$temp_file") || &open_error($temp_file);
    print TEMPFILE "$new_data";
    print  TEMPFILE "$new_line";
    close (TEMPFILE);
    close (DATABASE);
    rename ($temp_file, $data_file);
    &ReleaseFileLock ("$lock_file");

# Now print up the usual footer with an option to add another item.

    print <<"    end_of_html";
    <HTML><HEAD><TITLE>Your Item has been Modified</TITLE></HEAD>
    <BODY>
    <CENTER><H2>Your Item has been Modified</H2></CENTER>
    <FORM METHOD = "post" ACTION = "$database_manager_script_url">
    <CENTER>
    <INPUT TYPE = "hidden" NAME = "database" VALUE = "$setup_file">
    <INPUT TYPE = "hidden" NAME = "session_file"
           VALUE = "$form_data{'session_file'}">
    <INPUT TYPE = "submit" NAME = "add_form" VALUE = "Add an Item">
    <INPUT TYPE = "submit" NAME = "search_form_delete"
           VALUE = "Delete an Item">
    <INPUT TYPE = "submit" NAME = "search_form_modify"
           VALUE = "Modify an Item">
    <INPUT TYPE = "submit" NAME = "search_form_view"
           VALUE = "View the Database">
    </CENTER></FORM></BODY></HTML>
    end_of_html
    exit;
    }

#############################################################################
#                               &require                                    #
#############################################################################

# This subroutine checks to see whether the file that we are trying to 
# require actually exists and is readable by us.  The reason for this 
# subroutine is to provide the developer with an informative error message 
# when attempting to debug the scripts.

sub require
  {

# Define $require_file as a local variable and set it equal to the 
# filename we sent when we called this routine.

  local (@require_files) = @_;

# Check to see if the file exists and is readable by us.  If so, go ahead 
# and require it.

  foreach $file (@require_files)
    {
    if (-e "$file" && -r "$file")
      {
      require "$file";
      }

# If not, send back an error message that will help us isolate the 
# problem with the script.

    else
      {
      print "I'm sorry, I was not able to open $require_file.  Would you
             please check to make sure that you gave me a valid filename
             and that the permissions on $require_file are set to allow me
             access?";
      exit;
      }
    }
  }


  sub create_input_form
    {

# First print out the a table header.  This subroutine takes BORDER, 
# CELLPADDING< CELLSPACING, and WIDTH as argumnts, thoughj we only use the 
# first three in this call.

    print "<TABLE BORDER = \"1\" CELLPADDING = \"4\" 
            CELLSPACING = \"4\">";

# Now we'll need to create an HTML form so that administrators can add 
# items to the database.  Thus, we must have one input field for each field 
# in the database (except for database id field which is set by this script 
# and not by the administrator).  We'll get the list of database fields 
# from the @field_names array and for every element in the array, create an 
# input field.  However, we'll need to send the &build_input_form 
# subroutine a few things: the Name of the field, the variable to be 
# associated with that name, and the type of input we are going to use 
# (ie: textarea, text, select)

    foreach $field_name (@field_names)
      {
      print &build_input_form("$FIELD_ARRAY{$field_name}", 
                            "$FORM_COMPONENT_ARRAY{$field_name}", 
                            $field_name);
      }

  }


  sub search_database
    {

    local($submit_type) = @_;

# First, open the database file and
# begin checking each field in every row against the keywords submitted.

  $number_of_hits = "0";
  open (DATABASE, "$data_file");
  while (<DATABASE>)
    {
    $database_row = $_;

# Set $not_found_flag = 0 to make sure that it has not been initialized
# elsewhere.  The $not_found_flag variable will be used to keep track of
# whether or not a hit was made based on the client submitted keyword. If
# a match was found, the variable is going to equal 1, but more on that i
# a bit...

    $not_found_flag = "0";

# Make sure to disregaurd any line that is a database comment line.

    unless ($database_row =~ /^COMMENT:/)
      {

# Split up the database row into the @row array

      @row = split(/\|/,$database_row);

# For each key in the %form_data associative array, set $field_number =
# -1.  The reason that we want to do this is because we have both the
# pesky "submit" and "exact match" key/value pairs possibly coming in
# along with the rest of the form data.  We do not want our script to search
# the database for those fields because they don't exist!  By setting
# $field_number = -1, we'll be able to filter out such non field keys with
# the following routine.

      foreach $form_data_key (keys %form_data)
        {
        $field_number = -1;

# Now we will go through the fields in the database (@field_values),
# checking to see if there is a corresponding value coming in from the
# form ($form_data_key).  However, because arrays are counted from 0
# rather than from one, and because @field_values gives us a count of
# the array starting at one, we need to offset our counter by one.
# Thus, if the form "key" submitted is indeed a field in the database,
# $field_number ($y - 1) will be its actual location in the array.

        for ($y = 1; $y <= @field_values; $y++)
          {
          if ($form_data_key eq @field_values[$y-1] &&
              $form_data{"$form_data_key"} ne "")
            {
            $field_number = $y - 1;
            last; # Exit out of the for loop because we have verified field
            }
          } # End of for loop

# Now, we need to check the submitted value against the value in the
# database.  However, we need to make sure that the value is not "on" or
# "submit keyword".  If $field_number is still equal to -1, that means
# that we did not match the form data key against an actual database field
# so we should try the next key.  Otherwise, we know that we have a valid
# field to check against.  Again, $field_number must be <= -1 because of
# the array starting from 0.

        if ($field_number > -1)
          {

# Now perform the match, checking the database information against the
# submited keyword for that field.  First let's perform an exact
# match test.  If $form_data{'exact_match'} eq "" it means that the exact
# match check box was not checked.  The match is pretty straight forward.
# If the keyword string ($form_data{"$form_data_key"}) matches (=~) a
# string in the field were searching (@row[$field_number]) case
# insensiitively (/i), then we know we got a hit!

          if ($form_data{'exact_match'} eq "")
            {
            unless (@row[$field_number] =~/$form_data{"$form_data_key"}/i)
              {

# If there was no match, we'll set $not_found_flag = 1 so that in the end,
# if we get through all the fields and have still not found a match we
# will be able to tell the client that no matches were found.

              $not_found_flag = "1";
              last; # Exit out of ForEach keys in FormData
              } # end of unless
            } # end of if ($form_data{'exact_match'} eq "")

# On the other hand, the client may have clicked the exact match
# checkbox...

          else
            {

# This time, we'll proceede with an exact match using the \b though
# keeping it case insensitive (/i).  The same $not_found_flag setting will
# apply.

            unless (@row[$field_number] =~/\b$form_data{"$form_data_key"}\b/i)
              {
              $not_found_flag = "1";
              last; # Exit out of ForEach keys in FormData
              } # end of unless
            } # end of else
          } # End of if ($field_number > -1)
        } #End of ForEach keys in FormData

# Now, if we have found a match ($not_found_flag still equals "0"), we
# need to create a table row for the output.  We'll create a variable
# called $search_results which is going to collect all of the hits
# formatted as table rows for the output.  A hit will add each of the
# fields of the database row to a table row.

        if ($not_found_flag eq "0")
          {
          $number_of_hits++;
          if ($number_of_hits > "20")
            {
            $search_notice .= "This search engine will only return 20
                                hits, however, your search turned up more
                                than that.  Would you please refine your
                                search?";
            last;
            }          
          $hit_counter = "1";
          $db_id_number = pop (@row);
          push (@row, $db_id_number);

          if ($submit_type eq "delete")
	    {
	    $group_test = "$group_array[3]";
	    if ($group_test eq "")
	      {
	      $permission = "no";
	      }
	    }
	  if ($submit_type eq "modify")
	    {
	    $group_test = "$group_array[2]";
	    if ($group_test eq "")
	      {
   	      $permission = "no";
	      }
 	    }

          $search_results .= "<TR>";

          if ($permission eq "no")
	    {
            print <<"            end_of_html";
	    </CENTER><BLOCKQUOTE>
	    I am sorry, it appears that you do not have permission to 
    	    $submit_type.  Please contact the database administrator to find 
	    out how to gain access.  Sorry about that!
	    </BLOCKQUOTE><CENTER>
	    <INPUT TYPE = "hidden" NAME = "database" VALUE = "$setup_file">
	    <INPUT TYPE = "hidden" NAME = "session_file" 
		   VALUE = "$session_file">
	    <INPUT TYPE = "submit" NAME = "add_form" VALUE = "Add an Item">
	    <INPUT TYPE = "submit" NAME = "search_form_delete"
	           VALUE = "Delete an Item">
	    <INPUT TYPE = "submit" NAME = "search_form_modify"
	           VALUE = "Modify an Item">
	    <INPUT TYPE = "submit" NAME = "search_form_view"
	           VALUE = "View the Database">
            end_of_html
	    exit;
	    }


          if ($submit_type ne "none") 
            {
            $search_results .= "<TD ALIGN = \"center\">\n";
            $search_results .= "<INPUT TYPE = \"radio\" NAME = \"$submit_type\"
			               VALUE = \"$db_id_number\">";
            $search_results .= "\n</TD>\n";
            }

          foreach $field (@row)
            {
            $search_results .= "<TD>$field</TD>\n";
            }
          } # End of if ($not_found_flag eq "0")

          $search_results .= "</TR>\n";

       } # End of unless ($database_row =~ /^COMMENT:/)
     } # End of while (<DATABASE>)

    close (DATABASE);

# Now let's add a routine to handle the possibility that a client
# submitted keyword turns up nothing in the search. At this point, if
# $hit_counter is not equal to 1, it means that the search never turned
# up a hit.  Thus we'll send back a note to the client with a link back to
# the search form.  Notice that we'll use a hyperlink rather than a submit
# button because we want the client to access this script with out a
# CONTENT_LENGTH so that the form will pop up.  Also, we'll exit the
# routine here if no hits were found because we do not want to print up an
# empty table.

    if ($hit_counter ne "1")
           {
           print "I'm sorry, I was unable to find a match for the
                  keyword that you specified in the field that you
                  specified.  Feel free to
                  <A HREF = \"database_search.cgi\">try again</A>";
           print "</CENTER></BODY></HTML>";
           exit;
           }

    }
