#!/usr/bin/perl
########################
#
# guestbook cgi application demo for web perl class
#
# The assignment was to do this both with and without CGI.pm;
# this is the "fly-by-night roll-your-own" version - just to 
# see what's going on on under the hood.
#
# The point is three fold : 
#   (a) to see how to use CGI.pm
#   (b) to get more practice writing a perl/cgi, including file I/O
#   (c) to see how form input/output is handled.
#
# To use this thing, just point your browser at it and follow the directions.
#
# Many of these strings have space converted to %20 and things like that,
# with "URL encoding" : see for example 
# http://www.blooberry.com/indexdot/html/topics/urlencoding.htm
#
# This version is a mess :
# I haven't tested it much, and don't recommend doing things this way.
# It's just nice to be able to see what's going on under the hood.
#
# Note that the web server must be able to read/write 
# the guestbook file in this directory; 
# with the setuid scripts running in the /home/user/html/cgi/ directories,
# that means everything (including the directory) should be set 
# to "chmod 755".  Remember that incorrect permissions are the cause
# of 4 out of 5 web script problems.  Your mileage may vary.
# 
# As it exists, here, this script is not particularly secure.
# Can you see how to do any upleasant stuff with it?
#
# And there are some behaviors which aren't really the best - 
# in particular, once a user has given a username, they can't change it...
#
# Jim Mahoney
# v0.1 Sep 27 2004
########################
use strict;
use warnings;
#use CGI qw(:standard);
#use CGI::Carp qw(fatalsToBrowser);

my $title         = "Jim's Other Guestbook";
my $filename      = "./guestbook_data_two.txt";
my $cookiename    = "jims_guestbook_cookie_two";

# Read and convert the cgi parameters by hand. (Ughh...)
# The standard input string will look like this (using show_env.cgi)
#     username=Jim+Mahoney&data=When+in+the+course+of+human+events%2C+...
my $stdin     = <>;                     # any on standard input?
my %params    = split(/=|&/, $stdin);   # split apart to hash on = and & chars
my $new_entry = $params{data};
$new_entry =~ s/%20/ /g;                # change %20 to space everywhere 
$new_entry =~ s/\+/ /g;                 # and change + to space everywhere 
# To do this right, we'd do a more thorough encoding conversion.

# Grab the cookies from the environment, and parse 'em.  (Ugghh...)
# The string will look something like (using show-env.cgi to see it)
#    jims_guestbook_cookie_two=Jim
# though with spaces in the name it'll get messier...
my $cookiestring = $ENV{HTTP_COOKIE};
my %cookies = ();
%cookies   = split(/; |=/, $cookiestring) if $cookiestring;
my $username  = $cookies{$cookiename} || $params{username};
$username =~ s/ |%20/_/g;    # Change spaces, %20's to underbars
$username =~ s/\+/_/g;       # same for + signs
$username =~ s/\.//g;        # and remove periods, if any.

my $error_message = '';
if ($new_entry and not $username){
  $error_message = q{<font color="darkred"> } . 
                   q{Please enter your name as well as a message.</font>};
}

output_to_file($new_entry, $username, $filename) if ($new_entry and $username);
my $all_entries = read_from_file($filename);

# print the HTTPD headers
print "Set-cookie: $cookiename=$username; path=/\n";
print "Content-type: text/html\n\n";

# print the starting HTML stuff
print qq{
 <?xml version="1.0" encoding="iso-8859-1"?>
 <!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" 
       lang="en-US" xml:lang="en-US">
 <head><title>$title</title></head>
 <body bgcolor="#FFFFFF">
 <form method="POST">
  <h1>$title</h1>
  $error_message
  },
  html_page($all_entries, $username),
  qq{</form></body></html>}
  ;

# Seeing what's going on : put this line for the <form> tag :
#   <form method="POST" action="/on-campus/testing/show-env.cgi">

# == subroutines =====================================================

# Input: guestbook entries text
# Output: a string with the HTML body of the guestbook page. 
#  (Don't put the starting html or form stuff; we're using CGI.pm for that.)
sub html_page {
  my ($guestbook_entries, $username) = @_;
  my $html;
  if ($username){
    $html .= qq{ <b>Hi $username</b>, welcome back.<br />
      Would you like to leave another note?<p />
    };
  }
  else {
    $html .= qq{<p />
      Enter your name and some text in the provided fields below.<br />
      Then just click the button...<p />
      Your name: <input name="username" type="text" value=""><p />
    };
  }
  $html .= qq{
    <table><tr>
    <td valign="top">Your words of wisdom : </td>
    <td><textarea name="data" rows="8" 
         cols="40">\n  So type something already... </textarea></td>
    </tr></table>
    <input type="submit" value="Click here." />
    <hr noshade size=1>
  };
  $html .= $guestbook_entries if $guestbook_entries;
  $html .= qq{
    <div align="right">
      Questions?  Send some mail to Jim Mahoney
      (<a href="mailto:mahoney\@marlboro.edu">mahoney\@marlboro.ddu</a>).<br />
      <small><a href="with_CGIpm.cgi_html">view source</a></small>
     
    </div>
  };
  return $html;
}

# Inputs:    
#   text      to append to the guestbook, 
#   username  of who's doing it, 
#   filename  where it'll be stored.
# Sideffect: 
#   appends an entry to the given file,
#   with a username, date, and a bit of formatting.
# Output:
#   none
sub output_to_file {
  my ($text, $username, $filename) = @_;
  open DATA, ">> $filename" 
    or die "Oops - couldn't open '$filename' for writing";
  print DATA qq{<table><tr><td><font color="darkgreen"> $username on }
             . scalar(localtime()) . " writes </font></td></tr><tr><td>\n"
             . "<pre>$text</pre>\n"
             . "</td></tr></table>\n"
             . "<hr noshade size=1>";
  close DATA
}

# Input:  filename
# Output: all text from the file as a single string
sub read_from_file {
  my ($filename) = @_;
  return '' unless -e $filename;
  open DATA, "< $filename"
    or die "oops - couldn't open '$filename' for reading";
  my @lines = <DATA>;
  return join('', @lines);
}
