#!/usr/bin/perl

#
# A fabuluous gift registry app
#
# Chris Horn
# last modified 6 aug 2004
#
# This program is released under the
# Attribution-NonCommercial-ShareAlike 2.0 Creative Commons license
#
# A quick-read version of the license can be found here:
# http://creativecommons.org/licenses/by-nc-sa/2.0/
#
# The full license code can be found here:
# http://creativecommons.org/licenses/by-nc-sa/2.0/legalcode
#

use strict;
use DBI qw(:sql_types);
use CGI;
use CGI::Session qw(-ip-match);
use Socket;

# buffer-me-not
$|=1;

# --------------------------------------------------------------------------- #


# this is the public URL of the script
# use the localhost verion for testing
#
my $SCRIPTURL = 'http://www.beefstew.net/registry/giftreg.pl';
#my $SCRIPTURL = 'http://www.beefstew.net/registry/gift.pl';

# domain you can add and delet stuff from
#
#my @ADMIN_DOMAINS = ( 'speakeasy.net', 'beefstew.net', 'localhost' );
my $ADMIN_USER = 'admin';
my $ADMIN_PASS = 'password';

# contact in case of error
#
my $EMAIL = 'chris@beefstew.net';

# be sure your script has write access to this directory
# this path is on the server, it is not a URL
#
my $DB_FILE = 'jenny-chris.sqlite';

# this is the title of your registry.  it will be used to greet
# people and as the title of the webpage
#
my $REG_TITLE = "Chris &amp; Jenny's Wedding Registry";

# Leave this empty for the link to not print, otherwise
# this will give people a way back to the main parent page/site
#
my $PARENT_LINK = 'http://www.beefstew.net/wedding/';

# --------------------------------------------------------------------------- #

# set up a new session or continue an old one
#
my $cgi = new CGI;

CGI::Session->name("giftreg_SESSID");
my $session = new CGI::Session( "serializer:Storable", $cgi, {Directory => '/tmp'} );
$session->expire('+36h');

# create a cookie each time, but we have to set it either in the standard
# header or in the special redirect headers
my $cookie = $cgi->cookie(giftreg_SESSID => $session->id() );

&init(\$cgi, \$session);

my $logged_in = 0;
if ($session->param("~logged-in")) { $logged_in = 1; }

my $dbh = DBI->connect("dbi:SQLite:dbname=$DB_FILE","","", {RaiseError => 1, AutoCommit => 1} ) or
  die "Could not connect to the DB $DB_FILE.  Please check permissions and... stuff";

# if this is a brand new DB, create a gifts table
# I'm sure this is not the best way to do it...
if ( -z $DB_FILE ) {
	$dbh->do("CREATE TABLE gifts (id INTEGER,
								  title TEXT,
								  description TEXT,
								  link TEXT,
								  price INTEGER,
								  quantity INTEGER,
								  purchased INTEGER,
								  rank INTEGER,
								  quant_purchased INTEGER )" ) ;
}

# debugging aids
#
#print "Content-type: text/html\n\n";
#foreach my $key ( keys(%ENV) ) {	
#	print "$key = $ENV{$key}<br />\n";
#}
#foreach my $key ( keys(%in) ) {	
#	print "$key = $in{$key}<br />\n";
#}


if ( $cgi->param("login") eq "popup" ) {

	&PrintHeader();
	
	print <<__EOF__;
	<title>Login to $REG_TITLE</title></head><body>
	<center><form action="$SCRIPTURL" method="POST">
	
	<h3>Login to $REG_TITLE</h3>
	<p>Logging in gives you the ability to manage the registry</p>
	
	<table border="0" cellpadding="2">
	<tr><td>Username: <input type="text" size="12" name="login_name" /></td></tr>
	<tr><td>Password: <input type="password" size="12" name="login_pass" /></td></tr>
	
	<tr><td style="text-align: center;">
	<input type="submit" value="Login" /> 
	<input type="button" name="cancel" value="Cancel" onclick='parent.close()'>
	</td></tr>
	
	</table></form></center>
__EOF__

	&CloseUpPage();


# --------------------------------------------------------------------------- #
#
# if this is a login attept, close the popup and reload the main page
# thanks to Gallery, for the methods!
#
} elsif ($cgi->param("login_name") and $cgi->param("login_pass")) {

	print $cgi->header( -cookie=>$cookie );
	print "<body onload='opener.location.reload(); parent.close()'>";
	&ClosePageUp;

# --------------------------------------------------------------------------- #
#
# if this is a logout clear the ~logged-in key and reload
# for some reason, just clearing the key and redirecting to the ?view=1 didn't
# work
#
} elsif ( $cgi->param("logout") ) {

	$session->clear(["~logged-in"]);
	&PrintHeader;
	print "<body onload='opener.location.reload(); parent.close()'>";
	&CloseUpPage;

# --------------------------------------------------------------------------- #
#
# display a page for adding items to the registry
#
} elsif ( $cgi->param("additems") == 1 ) {

	&PrintHeader();
	
	if ( not $logged_in ) {	
		print <<__EOT__;
	Please <a href="$SCRIPTURL?login=popup" id="popuplink_1" onclick="javascript:nw=window.open(document.getElementById('popuplink_1').href,'Edit','height=500,width=500,location=no,scrollbars=yes,menubars=no,toolbars=no,resizable=yes');nw.opener=self;return false;">login</a> before trying to add an item.
	<br />&nbsp;<br />
__EOT__
		&CloseUpPage;
		exit 0;
	}

	print "<title>Add Items to the Registry</title>\n";
	print "</head>\n<body>\n";
	
	print "<h2>Add Items to the Registry</h2>\n";
	print "<p>Enter the requested information into the fields and click the 'Add Items' button. <br />";
	print "If you don't enter a title, that item's information will be ignored.</p>\n";
	
	print "<form action=\"$SCRIPTURL\" method=\"post\">\n";
	print "<input type=\"hidden\" name=\"postitems\" value=\"1\"/>\n";
	
	print "<table align=\"center\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\">\n";
	
	for (my $i=1; $i<=5; $i++) {
		
		my $bg;
		if ($i % 2 == 0) {
			$bg = "bg_even";
		} else {
			$bg = "bg_odd";
		}
		print "<tr><td><font size=\"400%\">$i &nbsp;&nbsp;</font></td><td>\n";
    	print "<table border=\"0\" cellpadding=\"4\" cellspacing=\"0\">";
    	print <<__ENTRY_FIELD__;
	
	<tr class="$bg">
	<td>Title:</td><td><input type="text" name="title_$i" size="95" /></td>
	</tr><tr class="$bg">
	<td>Description:</td><td><textarea name="desc_$i" rows="3" cols="71"></textarea></td>
	</tr><tr class="$bg">
	<td>URL:</td><td><input type="text" name="url_$i" size="95" /></td>
	</tr><tr class="$bg">
	<td>Price:</td><td><input type="text" name="price_$i" size="8" /> (number only)</td>
	</tr><tr class="$bg">
	<td>Quantity:</td><td><input type="text" name="quantity_$i" size="3" value="1" /></td>
	</tr>
	
    <!-- <tr><td colspan="2">&nbsp;</td></tr> -->
    
__ENTRY_FIELD__

		print "</table>\n";
		print "<br />";
		print "</td></tr>\n";

	}
	

	print "<tr><td colspan=\"2\" style=\"text-align: right\"><input type=\"submit\" value=\"Add Items\" /></td></tr>";

	print "</table></form>\n";
	#print "</div>";
	&CloseUpPage;

# --------------------------------------------------------------------------- #
#
# add submitted items to the DB and ask the user what to do
#
} elsif ( $cgi->param("postitems") == 1 ) {

	&PrintHeader();

	if ( not $logged_in ) {	
		print <<__EOT__;
	Please <a href="$SCRIPTURL?login=popup" id="popuplink_1" onclick="javascript:nw=window.open(document.getElementById('popuplink_1').href,'Edit','height=500,width=500,location=no,scrollbars=yes,menubars=no,toolbars=no,resizable=yes');nw.opener=self;return false;">login</a> before trying to add an item.
	<br />&nbsp;<br />
__EOT__
		&CloseUpPage;
		exit 0;
	}

	foreach ( $cgi->param() ) {
		if (/^title_/ or /^desc_/ or /^url_/ ) {
			# Convert %XX from hex numbers to alphanumeric
			# and clean out non-safe characters
			my $string = $cgi->param($_);
			#$string =~ s/%(..)/pack("c",hex($1))/ge;
			$string =~ s/([^\w\s])/sprintf ("&#%d;", ord ($1))/ge;
			$string =~ s/[\n\r]+/\<br \/\>/g;
			$cgi->param(-name=>"$_",-value=>"$string");
			#$val =~ s/[^a-zA-Z0-9_:\/\.~&= '\"%#\-!\?,:]//g;
		}
	}

	print "<title>What Next?</title>\n";
	print "</head>\n<body>\n";
	
	# this command will be executed below with the actual data
	my $sth = $dbh->prepare( "INSERT INTO gifts VALUES (?,?,?,?,?,?,?,?,?)" );

	# foreach item to add...
	foreach my $key ( $cgi->param() ) {	
	
		# ...check to see if it has a non-empty title
		# if it does, we will add its data to the DB
		if ($key =~ /title_/ and $cgi->param($key) !~ /^\s*$/ ) {

			# postnum stores the int for which input group this title is for
			# we then use this int to pull out the various item details
			my $postnum = $key;
			$postnum =~ s/^title_//;
			
			# gifts table has structure
			# id INTEGER, title TEXT, description TEXT, link TEXT, price INTEGER, quantity INTEGER, purchased INTEGER, rank INTEGER
	
			my $id = time().rand(time());
			$id =~ s/\.//g;
			my $title = $cgi->param($key);
			my $desc = $cgi->param("desc_$postnum");
			my $link = $cgi->param("url_$postnum");
			my $price = $cgi->param("price_$postnum");
			my $quant = $cgi->param("quantity_$postnum");
			
			# clean up as appropriate for the data type
			$link =~ s/\s*//g;
			$price =~ s/[^0-9\.]//g;
			$quant =~ s/[^0-9]//g;
			
			$sth->execute($id, $title, $desc, $link, $price, $quant, 0, 'NULL',	0);
			# if what we're printing doesn't have a link, then don't make it a link
			if ($link !~ /^\s*$/) {
				print "Added <a href=\"$link\">$title</a> to the database<br />";
			} else {
				print "Added '$title' to the database<br />\n";
			}
		}
	}
	
	$sth->finish();
	print "<p>You can now either <a href=\"$SCRIPTURL?additems=1\">add more items</a> or ";
	print "<a href=\"$SCRIPTURL?view=1\">view the registry</a></p><br />";
	&CloseUpPage;

# --------------------------------------------------------------------------- #
#
# add submitted items to the DB and ask the user what to do
#
} elsif ( $cgi->param("edit") ) {

	&PrintHeader();

	if ( not $logged_in ) {	
		print <<__EOT__;
	Please <a href="$SCRIPTURL?login=popup" id="popuplink_1" onclick="javascript:nw=window.open(document.getElementById('popuplink_1').href,'Edit','height=500,width=500,location=no,scrollbars=yes,menubars=no,toolbars=no,resizable=yes');nw.opener=self;return false;">login</a> before trying to add an item.
	<br />&nbsp;<br />
__EOT__
		&CloseUpPage;
		exit 0;
	}
	
	my @item;
	my $sth = $dbh->prepare( q[ SELECT title,description,link,price,quantity,quant_purchased FROM gifts WHERE id=? ] );
	$sth->bind_param( 1, $cgi->param("edit"), SQL_VARCHAR );
	$sth->execute();
	$sth->bind_columns( \$item[0], \$item[1], \$item[2], \$item[3], \$item[4],	\$item[5] );
	$sth->fetch();
	$sth->finish();

	my $id = $cgi->param("edit");
	my $desc = $item[1];
	$desc =~ s/\<br \/\>/\n/g;

	print <<__EOT__;
	<title>Edit an Item in the Registry</title>
	</head><body>
	
	<h2>Edit $item[0]</h2>
	<p>Chage the information as you wish.<br />
	If you don't enter a title, this edit will fail.</p>
	
	<form action="$SCRIPTURL" method="post">
	<input type="hidden" name="commitedit" value="$id"/>
	
	<table border="0" cellpadding="4" cellspacing="0">
	<tr>
	<td>Title:</td><td><input type="text" name="title" value="$item[0]" size="95" /></td>
	</tr><tr>
	<td>Description:</td><td><textarea name="desc" rows="3" cols="71">$desc</textarea></td>
	</tr><tr>
	<td>URL:</td><td><input type="text" name="url" value="$item[2]" size="95" /></td>
	</tr><tr>
	<td>Price:</td><td><input type="text" name="price" value="$item[3]" size="8" /> (number only)</td>
	</tr><tr>
	<td>Quantity:</td><td><input type="text" name="quantity" value="$item[4]" size="3" value="1" /></td>
	</tr><tr>
	<td>Quantity Purchased:</td><td><input type="text" name="quant_purch" value="$item[5]" size="3" value="1" /></td>
	</tr>

	<tr><td colspan="2" style="text-align: center"><input type="submit" value="Commit Changes" /></td></tr>
	</table>

	</form>
	
	
__EOT__

	&CloseUpPage;

# --------------------------------------------------------------------------- #
#
# commit an edit 
#
} elsif ( $cgi->param("commitedit") ) {

	&PrintHeader();

	if ( not $logged_in ) {	
		print <<__EOT__;
	Please <a href="$SCRIPTURL?login=popup" id="popuplink_1" onclick="javascript:nw=window.open(document.getElementById('popuplink_1').href,'Edit','height=500,width=500,location=no,scrollbars=yes,menubars=no,toolbars=no,resizable=yes');nw.opener=self;return false;">login</a> before trying to add an item.
	<br />&nbsp;<br />
__EOT__
		&CloseUpPage;
		exit 0;
	}

	foreach ( $cgi->param() ) {
		if (/^title/ or /^desc/ or /^url/ ) {
			# Convert %XX from hex numbers to alphanumeric
			# and clean out non-safe characters
			my $string = $cgi->param($_);
			#$string =~ s/%(..)/pack("c",hex($1))/ge;
			$string =~ s/([^\w\s])/sprintf ("&#%d;", ord ($1))/ge;
			$string =~ s/[\n\r]+/\<br \/\>/g;
			$cgi->param(-name=>"$_",-value=>"$string");
			#$val =~ s/[^a-zA-Z0-9_:\/\.~&= '\"%#\-!\?,:]//g;
		}
	}

	# gifts table has structure
	# id INTEGER, title TEXT, description TEXT, link TEXT, price INTEGER, quantity INTEGER, 
	# purchased INTEGER, rank INTEGER, quant_purchased INTEGER

	my $id = $cgi->param("commitedit");
	my $title = $cgi->param("title");
	my $desc = $cgi->param("desc");
	my $link = $cgi->param("url");
	my $price = $cgi->param("price");
	my $quant = $cgi->param("quantity");
	my $quant_purch = $cgi->param("quant_purch");
	
	# clean up as appropriate for the data type
	$link =~ s/\s*//g;
	$price =~ s/[^0-9\.]//g;
	$quant =~ s/[^0-9]//g;
	$quant_purch =~ s/[^0-9]//g;

	if (not defined( $title ) or $title =~ /^\s*$/) {
		print "<title>There's a Problem!</title>\n";
		print "</head><body>\n";
		print "<h2>You must specify a title for the entry.</h2>\n\n";
		print "<p>You did not specify a title, so no changes have been made. ";
		print "Pressing back is probably your best bet, but you can also <a href=\"$SCRIPTURL?edit=$id\">re-edit</a> ";
		print "the entry from scratch.</p>\n\n";
		&CloseUpPage;
		exit 0;
	}

	my $sth = $dbh->prepare( q[ UPDATE gifts SET title=?,description=?,link=?,price=?,quantity=?,quant_purchased=?,purchased=? WHERE id=? ] );
	$sth->bind_param( 1, $title, SQL_VARCHAR );
	$sth->bind_param( 2, $desc, SQL_VARCHAR );
	$sth->bind_param( 3, $link, SQL_VARCHAR );
	$sth->bind_param( 4, $price, SQL_VARCHAR );
	$sth->bind_param( 5, $quant, SQL_VARCHAR );
	$sth->bind_param( 6, $quant_purch, SQL_VARCHAR );
	if ($quant_purch == 0) {
		$sth->bind_param( 7, 0, SQL_VARCHAR );
	} else {
		$sth->bind_param( 7, 1, SQL_VARCHAR );
	}
	$sth->bind_param( 8, $id, SQL_VARCHAR );

	$sth->execute();
	$sth->finish();

	print "<title>What Next?</title>\n";
	print "</head>\n<body>\n";
	
	# if what we're printing doesn't have a link, then don't make it a link
	if ($link !~ /^\s*$/) {
		print "<p>Updated information for <a href=\"$link\">$title</a> in the database</p><br />\n";
	} else {
		print "<p>Updated information for '$title' in the database</p><br />\n";
	}

	my $formatted_price = &CommaFormatted($price);
	my $formatted_quant = &CommaFormatted($quant);
	my $formatted_quant_purch = &CommaFormatted($quant_purch);

	print <<__EOF__;
	<div style="margin-left:15px;">
	
	<table border="0" cellpadding="1" cellspacing="0">
	<!-- ID: $id -->
	<tr><td style="text-align: right">Title: &nbsp;</td><td>$title</td></tr>
	<tr><td style="text-align: right">Link: &nbsp;</td><td><a href="$link">$link</a></td></tr>
	<tr><td style="text-align: right" valign="top">Description: &nbsp;</td><td>$desc</td></tr>
	<tr><td style="text-align: right">Price: &nbsp;</td><td>$formatted_price</td></tr>
	<tr><td style="text-align: right">Quantity: &nbsp;</td><td>$formatted_quant</td></tr>
	<tr><td style="text-align: right">Quantity Purchased: &nbsp;</td><td>$formatted_quant_purch</td></tr>
	</table>

	</div><br />
	<p>If this is not correct, please <a href="$SCRIPTURL?edit=$id">edit the entry</a> again.</p>
	<p>You can <a href="$SCRIPTURL?additems=1">add more items</a> or <a href="$SCRIPTURL?view=1">view the registry</a></p><br />
__EOF__

	&CloseUpPage;


# --------------------------------------------------------------------------- #
#
# view the registry DB
#
} elsif ( $cgi->param("view") == 1 ) {
	
	&PrintHeader();

	my ($table_width, $td_cols, $td1_width, $td2_width, $td3_width, $td4_width, $td5_width, $td5_width, $td6_width);
	if ($logged_in) {
		$td_cols = 6;
		$td1_width = 400;
		$td2_width = 140;
		$td3_width = 200;
		$td4_width = 40;
		$td5_width = 40;
		$td6_width = 40;
		$table_width = $td1_width + $td2_width + $td3_width + $td4_width + $td5_width + $td5_width;
	} else {
		$table_width = '70%';
		$td_cols = 3;
		$td1_width = 400;
		$td2_width = 140;
		$td3_width = 200;
		$td4_width = 0;
		$td5_width = 0;
		$td6_width = 0;
		$table_width = $td1_width + $td2_width + $td3_width + $td4_width + $td5_width + $td6_width;
	}


	print "<title>$REG_TITLE</title>\n";
	print "</head><body>\n";
	print "<h2>Welcome to $REG_TITLE!</h2>\n\n";
	
	if (not $logged_in) {
	print <<__EOT__;
	<div style="margin-right:8%; margin-top:-20px; text-align:right">
	<a href="$SCRIPTURL?login=popup" id="popuplink_1" onclick="javascript:nw=window.open(document.getElementById('popuplink_1').href,'Edit','height=500,width=500,location=no,scrollbars=yes,menubars=no,toolbars=no,resizable=yes');nw.opener=self;return false;">[login]</a>
	<br />&nbsp;<br />
	</div>
__EOT__
	} else {
	print <<__EOT__;
	<div style="margin-right:8%; margin-top:-20px; text-align:right">
	<a href="$SCRIPTURL?logout=1" id="popuplink_1" onclick="javascript:nw=window.open(document.getElementById('popuplink_1').href,'Edit','height=500,width=500,location=no,scrollbars=yes,menubars=no,toolbars=no,resizable=yes');nw.opener=self;return false;">[logout]</a>
	<br />&nbsp;<br />
	</div>
__EOT__
	}
	
	print <<__EOT__;
	<table align="center" width="$table_width" border="0" cellpadding="4" cellspacing="0"><tr><td colspan=\"$td_cols\">

	<p class="text_contents">Thanks for visiting our registry.  Below you'll find some gift <i>ideas</i>. 
	They're here simply because there are a decent number of people who want to look at a registry.  Please don't 
	feel obligated to purchase something from this list - in fact, don't feel like you have to purchase us anything at all!</p>

	<p class="text_contents">It's important that we note that we aren't actually registered anywhere.  Instead, Chris threw together 
	some code on his webserver to make this registry.  Therefore you are looking at a mere collection of links to places 
	where you can actually purchase stuff.  This list just serves as a way of communicating to others what's already been 
	purchased.  If you do purchase something from the list, please click the 'Mark as Purchased' link to the right of the entry 
	to remove the item from this page</p>
__EOT__
	
	if ( $PARENT_LINK =~ /http:\/\// ) {
		print "<p>Look no further for a link <a href=\"$PARENT_LINK\">back to the wedding page</a>.</p></td></tr>";
	} else {
		print "</td></tr>";
	}

	if ($logged_in) { print <<__EOT__
		<tr><td colspan="$td_cols" align="right"><p><a href="$SCRIPTURL?additems=1">Add More Items</a> to your registry!</p></td></tr>
__EOT__
	}

	my $i = 1;
	my $not_purchased = $dbh->selectall_arrayref("SELECT id,title,description,link,price,quantity,rank,quant_purchased FROM gifts WHERE purchased=0");
	foreach my $item (@$not_purchased) {
	
		# choose which background color for this row
		my $bg;
		if ($i % 2 == 0) {
			$bg = "bg_even";
		} else {
			$bg = "bg_odd";
		}
		$i++;
		print "<tr class=\"$bg\"><td width=\"$td1_width\">";

		# if what we're printing doesn't have a link, then don't make it a link
		if ($$item[3] !~ /^\s*$/) {
			print "<a href=\"$$item[3]\">$$item[1]</a><br />\n";
		} else {
			print "$$item[1]<br />\n";
		}
		
		# print out the proper terminology
		# based on whether it's been all-the-way purchased or not
		my ($string, $quant, $price);
   		$quant = &CommaFormatted($$item[5]);
		$price = &CommaFormatted($$item[4]);
		if ( $$item[7] >= 1 ) {
			$string = "Number remain: $quant";
		} else {
			$string = "Number desired: $quant";
		}
		
    	print <<__ENTRY_FIELD__;

		$$item[2]
	</td><td width="$td2_width">
		Price: &#36;$price<br />
		$string	
	</td><td width="$td3_width" valign="middle" align="center">
		<form action="$SCRIPTURL" method="post">
		<input type="hidden" name="purchase" value="$$item[0]" />
		<input type="text" name="quantity" size="3" maxlength="6" />
		<input type="submit" value="Mark as Purchased" />
		</form>
	</td>

__ENTRY_FIELD__
		if ($logged_in) {
    	print <<__ENTRY_FIELD__;

	<td align="right" width="$td4_width">
	&nbsp;
	<td align="center" width="$td5_width">
		<form action="$SCRIPTURL" method="post">
		<input type="hidden" name="delete" value="$$item[0]" />
		<input type="image" src="remove.png" alt="Remove" value="Remove" />
		</form>
	</td><td align="center" width="$td6_width">
		<form action="$SCRIPTURL" method="post">
		<input type="hidden" name="edit" value="$$item[0]" />
		<input type="image" src="edit.png" alt="Edit" value="Edit" />
		</form>
	</td>

__ENTRY_FIELD__

		}
		print "</tr>";
	}
	
	my $purchased = $dbh->selectall_arrayref("SELECT id,title,description,link,price,quantity,rank,quant_purchased,purchased FROM gifts WHERE quant_purchased>=1");
	if ($$purchased[0]) {
		print "<tr><td colspan=\"$td_cols\"><br />&nbsp;The Items Below Have Already Been Purchased</td></tr>\n";
	}
		
	foreach my $item (@$purchased) {
	
		# choose which background color for this row
		my $bg;
		if ($i % 2 == 0) {
			$bg = "bg_even";
		} else {
			$bg = "bg_odd";
		}
		$i++;
		print "<tr class=\"$bg\"><td width=\"$td1_width\">";

		# if what we're printing doesn't have a link, then don't make it a link
		if ($$item[3] !~ /^\s*$/) {
			print "<a href=\"$$item[3]\">$$item[1]</a><br />\n";
		} else {
			print "$$item[1]<br />\n";
		}

		# print out the proper terminology
		# based on whether it's been all-the-way purchased or not
		my ($string, $quant, $price);
		if ( $$item[8] == 1 ) {
	   		$quant = &CommaFormatted($$item[7]-$$item[5]);
			$price = &CommaFormatted($$item[4]);
			$string = "Number desired: $quant";
		} else {
			$quant = &CommaFormatted($$item[5]);
			$price = &CommaFormatted($$item[4]);
			$string = "Number remain: $quant";
		}
	 		print <<__ENTRY_FIELD__;

		$$item[2]
	</td><td width="$td2_width">
		Price: &#36;$price<br />
		$string	
	</td><td width="$td3_width" valign="middle" align="center">
		Number purchased: $$item[7]
	</td>

__ENTRY_FIELD__

	
		if ($logged_in) {
    	print <<__ENTRY_FIELD__;

	<td align="center" width="$td4_width">
		<form action="$SCRIPTURL" method="post">
		<input type="hidden" name="restore" value="$$item[0]" />
		<input type="image" src="uparrow.png" alt="Restore" value="Restore" />
		</form>
	</td><td align="center" width="$td5_width">
		<form action="$SCRIPTURL" method="post">
		<input type="hidden" name="delete" value="$$item[0]" />
		<input type="image" src="remove.png" alt="Remove" value="Remove" />
		</form>
	</td><td align="center" width="$td6_width">
		<form action="$SCRIPTURL" method="post">
		<input type="hidden" name="edit" value="$$item[0]" />
		<input type="image" src="edit.png" alt="Edit" value="Edit" />
		</form>
	</td>

__ENTRY_FIELD__

		}
		print "</tr>";

	}

	print "</table>\n";
	&CloseUpPage;

# --------------------------------------------------------------------------- #
#
# mark an item as purchased
#
} elsif ( defined($cgi->param("purchase")) ) {

	&PrintHeader();

	# check the quantity was specified properly (non-zero & numerical)
	my $quantity = $cgi->param("quantity");
		
	if (not defined( $cgi->param("quantity") ) or $cgi->param("quantity") == 0 or $quantity =~ m/[^0-9]/g) {
		print "<title>There's a Small Problem!</title>\n";
		print "</head><body>\n";
		print "<h2>Thanks, but there's a small problem.</h2>\n\n";
		print "<p>You seemed to have mis-typed the quantity.  Please <a href=\"$SCRIPTURL?view=1\">go back</a> and try again.  Thanks.</p>\n\n";
		&CloseUpPage;
		exit 0;
	}
	
	print "<title>Thank You!</title>\n";
	print "</head><body>\n";
	print "<h2>Thanks for your gift and for using our registry!</h2>\n\n";

	my @item;
	my $sth1 = $dbh->prepare( q[ SELECT id,title,description,link,price,quantity,quant_purchased FROM gifts WHERE id=? ] );
	$sth1->bind_param( 1, $cgi->param("purchase"), SQL_VARCHAR );
	$sth1->execute();
	$sth1->bind_columns( \$item[0], \$item[1], \$item[2], \$item[3], \$item[4],	\$item[5], \$item[6] );
	$sth1->fetch();
	$sth1->finish();
	
	my $formatted_quant = &CommaFormatted($quantity);
	my $formatted_price = &CommaFormatted($item[4]);
	
	print <<__EOF__;
	<p>Here's what you've chosen:</p>
	<div style="margin-left:15px;">
	<!-- ID: $cgi->param("purchase") -->
	Title: $item[1]<br />
	Link: <a href="$item[3]">$item[3]</a><br />
	Description: $item[2]<br />
	Price: &#36;$formatted_price<br />
	Quantity: $formatted_quant<br />
	</div>
	<p>If this is not correct, please email <a href="mailto:$EMAIL">$EMAIL</a> with the information above.</p>
	<p>If this <em>is</em> correct, either close the window or go back to the <a href="$SCRIPTURL?view=1">registry</a>.</p>
__EOF__

	# we need to deduct this item from the registry
	# if someone purchases more than the requested quantity, the overage is
	# stored in the quantity field
	#
	# all-the-way purchased is indicated by the purchased flag being 1
	if ( $cgi->param("quantity") >= $item[5] ) {
		my $sth = $dbh->prepare( q[ UPDATE gifts SET quantity=?,purchased=1,quant_purchased=? WHERE id=? ] );
		$sth->bind_param( 1, int($cgi->param("quantity") - int($item[5])), SQL_VARCHAR );
		$sth->bind_param( 2, int($item[6]) + int($cgi->param("quantity")), SQL_VARCHAR );
		$sth->bind_param( 3, $cgi->param("purchase"), SQL_VARCHAR );
		$sth->execute();
		$sth->finish();
	} else {
		my $sth = $dbh->prepare( q[ UPDATE gifts SET quantity=?,quant_purchased=? WHERE id=? ] );
		$sth->bind_param( 1, int($item[5]) - int($cgi->param("quantity")), SQL_VARCHAR );
		$sth->bind_param( 2, int($item[6]) + $cgi->param("quantity"), SQL_VARCHAR );
		$sth->bind_param( 3, $cgi->param("purchase"), SQL_VARCHAR );
		$sth->execute();
		$sth->finish();
	}

	&CloseUpPage;

# --------------------------------------------------------------------------- #
#
# delete an item from the registry
#
} elsif ( defined($cgi->param("delete")) ) {

	if (not $logged_in) {	
		&PrintHeader();
		print <<__EOT__;
	Please <a href="$SCRIPTURL?login=popup" id="popuplink_1" onclick="javascript:nw=window.open(document.getElementById('popuplink_1').href,'Edit','height=500,width=500,location=no,scrollbars=yes,menubars=no,toolbars=no,resizable=yes');nw.opener=self;return false;">login</a> before trying to add an item.
	<br />&nbsp;<br />
__EOT__
		&CloseUpPage;
		#print "<title>Forbidden</title>\n";
		#print "</head>\n<body>\n";
		#print "You can not delete items from the registry if you're not logged in.\n";
		#&CloseUpPage;
		exit 0;
	}
	
	my $sth = $dbh->prepare( q[ DELETE FROM gifts WHERE id=? ] );
	$sth->bind_param( 1, $cgi->param("delete"), SQL_VARCHAR );
	$sth->execute();
	$sth->finish();
	$dbh->disconnect();

	print $cgi->header( -cookie=>$cookie, -Location=>"$SCRIPTURL?view=1" );


# --------------------------------------------------------------------------- #
#
# restore an item to the registry to-be-purchased list
#
} elsif ( $cgi->param("restore") ) {

	if (not $logged_in) {	
		&PrintHeader();
		print <<__EOT__;
	Please <a href="$SCRIPTURL?login=popup" id="popuplink_1" onclick="javascript:nw=window.open(document.getElementById('popuplink_1').href,'Edit','height=500,width=500,location=no,scrollbars=yes,menubars=no,toolbars=no,resizable=yes');nw.opener=self;return false;">login</a> before trying to add an item.
	<br />&nbsp;<br />
__EOT__
		&CloseUpPage;
		#print "<title>Forbidden</title>\n";
		#print "</head>\n<body>\n";
		#print "You can not manage items on the registry if you're not logged in.\n";
		#&CloseUpPage;
		exit 0;
	}

	my @item;
	my $sth = $dbh->prepare( q[ SELECT purchased,quantity,quant_purchased FROM gifts WHERE id=? ] );
	$sth->bind_param( 1, $cgi->param("restore"), SQL_VARCHAR );
	$sth->execute();
	$sth->bind_columns( \$item[0], \$item[1], \$item[2] );
	$sth->fetch();
	$sth->finish();

	my $desired;
	# if it was all-the-way purchased, reinstate the desired amount
	if ( $item[0] == 1 ) {
		$desired = $item[2] - $item[1];
	} else {
		$desired = $item[1] + $item[2];
	}

	# we need to reinstate this item in the registry
	$sth = $dbh->prepare( q[ UPDATE gifts SET quantity=?,purchased=0,quant_purchased=0 WHERE id=? ] );
	$sth->bind_param( 1, $desired, SQL_VARCHAR );
	$sth->bind_param( 2, $cgi->param("restore"), SQL_VARCHAR );
	$sth->execute();
	$sth->finish();
	$dbh->disconnect;

	#print "Location: $SCRIPTURL?view=1\n\n";
	#print "Content-type: text/plain\n\n";
	#$cgi->header(-cookie => $cookie);
	print $cgi->header( -cookie=>$cookie, -Location=>"$SCRIPTURL?view=1" );

	
# --------------------------------------------------------------------------- #
#
# unsupported action
#
} else {

	print $cgi->header( -cookie=>$cookie, -Location=>"$SCRIPTURL?view=1" );

}



# --------------------------------------------------------------------------- #
#
# close out the XHTML
#
sub CloseUpPage {

	$dbh->disconnect;

	print <<__EOT__;

<div style="text-align: right;">
	<br />&nbsp;<br />&nbsp;<br />
	<a href="http://validator.w3.org/check/referer">
	<img style="border:0;width:88px;height:31px"
	src="http://www.w3.org/Icons/valid-xhtml10" alt="Valid XHTML 1.0"
	height="31" width="88" />
	</a>
</div>

</body>
</html>

__EOT__

}

sub PrintHeader {
	# We're always going to generate a web page as our output, so let's make it a XHTML 1.0 compliant one!
	#
	print $cgi->header( -cookie=>$cookie );

	print <<__EOT__;

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
	
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />

<link rel="stylesheet" href="http://www.beefstew.net/wedding/wedding.css" type="text/css" />

<!--  If you'd like to embed the stylesheet in the HTML, skip to down around line 915
      of the script, comment out the <link> tag above and and uncomment this <style> block

<style type="text/css">

	body {
		font-family:helvetica, arial, sans-serif;
	}
	
	.bg_even {
		background-color: #acd;
	}
	
	.bg_odd {
		background-color: #c4bea2;
	}
</style>
-->

__EOT__

}

# returns a 1 if REMOTE_ADDR is a member of an allowed domain
# and 0 if its not
#
sub CheckDomain {

	my $valid_domains = shift;
	my $allowed = 0;
	
	my $remoteip = pack('C4', split( /\./, $ENV{'REMOTE_ADDR'} ) );
    my ( $host, $aliases, $addrtype, $length, @addr ) = gethostbyaddr( $remoteip, AF_INET );

	foreach my $domain (@$valid_domains) {
		#print "checking $host against $domain<br />";
		if ($host =~ /$domain$/) {
			$allowed = 1;
			last;
		}
		my @aliases = split /\s/, $aliases;
		foreach (@aliases) {
			#print "checking $_ against $domain<br />";
			if (/$domain$/) {
				$allowed = 1;
			}
			last;
		}
	}
	return( $allowed );
}


# heavily based upon sample code from
# http://search.cpan.org/~sherzodr/CGI-Session-3.95/Session/CookBook.pm
#
sub init {

	my $cgi = shift;
	my $session = shift;

	if ( $$session->param("~logged-in") ) {
		return 1;  # if logged in, don't bother going further
	}

	my $login_name = $$cgi->param("login_name") or return;
	my $login_passwd= $$cgi->param("login_pass") or return;

	# if we came this far, user did submit the login form
	# so let's try to load his/her profile if name/psswds match
	if( my $profile =_load_profile($login_name, $login_passwd) ) {
		$$session->param("~logged-in", 1);
		return 1;
	}

	# if we came this far, the login/psswds do not match
	# the entries in the database
	return 0;
}

# this doesn't so much as load a profile a just check
# the username password of the user
sub _load_profile {

	my ($login_name, $login_passwd) = @_;

	if ($login_name eq $ADMIN_USER and $login_passwd eq $ADMIN_PASS) {
		return 1;
	} else {
		return undef;
	}
}

sub CommaFormatted {

	my $delimiter = ',';
	my($n,$d) = split /\./,shift,2;
	my @a = ();
	while($n =~ /\d\d\d\d/) {
		$n =~ s/(\d\d\d)$//;
		unshift @a,$1;
	}
	unshift @a,$n;
	$n = join $delimiter,@a;
	$n = "$n\.$d" if $d =~ /\d/;
	return $n;
}

