Приглашаем посетить
Feedback Admin
#!/usr/local/bin/perl
############################################################################
# #
# FeedbackAdmin Version 3.0 #
# Written by Matthew Wright mattw@worldwidemart.com #
# Created 6/5/96 Last Modified 3/24/97 #
# #
# Copyright 1997 Craig Patchett & Matthew Wright. All Rights Reserved. #
# This program is part of The CGI/Perl Cookbook from John Wiley & Sons. #
# License to use this program or install it on a server (in original or #
# modified form) is granted only to those who have purchased a copy of The #
# CGI/Perl Cookbook. (This notice must remain as part of the source code.) #
# #
############################################################################
############################################################################
# Define configuration constants #
############################################################################
# If you are on a Unix machine, set this to 1, otherwise, if you are on
# another platform it must be set to 0 so that the encrypt function will not
# be activated.
$ENCRYPT = 1;
# This URL, if filled in, will link to important information in the
# README HTML file, when Feedback generates an error.
$README = 'http://www.domain.com/feedback/README.html';
# $WEB_SERVER is the host name of your web server. If the name of your web
# server is host.xxx, set this to 'host.xxx'.
$WEB_SERVER = 'domain.com';
# $CONFIG_DIR is the path where config files can be stored.
$CONFIG_DIR = '/home/protected/feedback/';
# $SMTP server is the server name of your SMTP server.
$SMTP_SERVER = 'smtp.domain.com';
# $LOCK_DIR is the default directory where all lock files will be placed.
$LOCK_DIR = '/tmp/';
# $MAX_WAIT is the max seconds lock will wait before removing the lock file.
$MAX_WAIT = 5;
# This is the directory in which all of the required routines are stored.
# By default these are placed in the require directory.
$REQUIRE_DIR = 'require';
############################################################################
# Get Required subroutines which need to be included. #
############################################################################
# Push the $REQUIRED_DIR onto the @INC array for include file directories.
if ($REQUIRE_DIR ne '') {
push(@INC, $REQUIRE_DIR);
}
# Require Necessary Routines for this script to run.
require 'parsform.pl';
require 'template.pl';
require 'locksubs.pl';
############################################################################
# Parse the form contents and put configuration fields into %CONFIG and #
# other fields in %FORM. #
############################################################################
if (!(&parse_form)) {
&error($Error_Message);
}
############################################################################
# If the config_file form field was found in valid path, require it. #
############################################################################
if ($FORM{'config_file'} !~ /^$CONFIG_DIR/) {
&error('Invalid Configuration File. Must appear in ' . $CONFIG_DIR);
}
require "$FORM{'config_file'}" || &error('config_file');
############################################################################
# If the user has selected Approve Posts, print out the form to do so. # #
############################################################################
if ($FORM{'type'} eq 'Approve Entries' && $APPROVE_FILE) {
open(APPROVE, $APPROVE_FILE)
|| &error('open->approve_file', $APPROVE_FILE);
# Print out the header for the HTML approve page.
&html_header('Feedback Admin: Approve Feedback Entries');
print "Use the entries below to specify whether you wish to Approve,\n";
print "Hold, or Remove the Entry from the Admin File. This form also\n";
print "allows you to specify users you wish to ban from posting to\n";
print "the feedback page. Simply check the checkbox next the Ban this\n";
print "hostname and IP address and the hostnames and IP addresses\n";
print "shown in parentheses on the line above will be banned from\n";
print "posting.<p>\n";
print "<form method=POST action=\"$ADMIN_CGI_URL\">\n";
print "<input type=hidden name=\"config_file\" value=\"$FORM{'config_file'}\">\n";
print "<input type=hidden name=\"action\" value=\"$FORM{'type'}\">\n";
if ($USE_PASSWD eq 'YES') {
print "Username: <input type=text name=\"username\"><br>\n";
print "Password: <input type=password name=\"password\"><p>\n";
}
print "<hr size=7 width=75%>\n";
# For each entry in the approve file, split it into it's contents.
while ($approve_line = <APPROVE>) {
# Localize variables and assign values.
local($entry_num, $date, $remote_host, $remote_addr, $form_string) =
split(/\|\|/, $approve_line);
# Get rid of previous config stuff from last loop through.
undef(%CONFIG);
# Define the new CONFIG variables for this loop through.
&define_config($form_string);
# Print the radio buttons allowing them to approve post, remove post
# or hold post and checkbox allowing for host banning.
print "<input type=radio name=\"$entry_num\" value=\"approve\"";
print "CHECKED> Approve Entry submitted on $date. ";
print "($remote_host - $remote_addr)<br>\n";
print "<input type=radio name=\"$entry_num\" value=\"hold\"> ";
print "Hold Entry For A Later Approval. <input type=radio ";
print "name=\"$entry_num\" value=\"remove\"> ";
print "Remove Entry from Admin File.<br>\n";
print "<input type=checkbox name=\"ban_host\"";
print "value=\"$remote_host||$remote_addr\">";
print "Ban this hostname and IP address from posting to the ";
print "feedback forum again.<p>\n";
# Show the entry as it will appear by calling the template parser.
if (!&parse_template($FEEDBACK_TEMPLATE, *STDOUT)) {
&error('open->feedback_template', $FEEDBACK_TEMPLATE);
}
# Print an entry separator.
print "<hr size=7>\n";
}
# Print the end of HTML page.
print "<center><input type=submit value=\"Approve Posts\"> ";
print "<input type=reset></center>\n";
print "</form>\n";
print "</body></html>\n";
close(APPROVE);
}
############################################################################
# If the user has selected to Remove Posts from the main admin page, print #
# out the form to do so. #
############################################################################
elsif ($FORM{'type'} eq 'Remove Entries' && $FEEDBACK_FILE) {
# Localize variables used in this subroutine.
local($entry_num, $date, $remote_host, $remote_addr);
# Open the feedback file and read in the lines.
open(FEEDBACK, $FEEDBACK_FILE)
|| &error('open->feedback_file', $FEEDBACK_FILE);
@feedback_lines = <FEEDBACK>;
close(FEEDBACK);
# Print the header of the feedback and top paragraph explaining page.
&html_header('Feedback Admin: Remove Feedback Entries');
print "Use the checkboxes below to specify which messages you\n";
print "wish to remove from the feedback page. This form also allows\n";
print "you to specify users you wish to ban from posting. Simply\n";
print "check the checkbox next to Ban this hostname and IP address\n";
print "and the hostnames and IP addresses shown in the parentheses\n";
print "on the line above will be banned from posting.<p>\n";
print "<form method=POST action=\"$ADMIN_CGI_URL\">\n";
print "<input type=hidden name=\"config_file\" ";
print "value=\"$FORM{'config_file'}\">\n";
print "<input type=hidden name=\"action\" value=\"$FORM{'type'}\">\n";
# If they are using a username/password verification, print these
# form fields.
if ($USE_PASSWD eq 'YES') {
print "Username: <input type=text name=\"username\"><br>\n";
print "Password: <input type=password name=\"password\"><p>\n";
}
# Print entry separator
print "<hr size=7>\n";
# Loop through feedback lines pulling out entries and displaying
# them for removal.
foreach $feedback_line (@feedback_lines) {
if ($feedback_line =~ /<!--Begin Entry: (.*)\|\|(.*)\|\|(.*)\|\|(.*)-->/) {
$entry_num = $1; $date = $2; $remote_host = $3; $remote_addr = $4;
$entry_status = "1";
print "<input type=checkbox name=\"$entry_num\" ";
print "value=\"remove\"> Remove Feedback Entry Number $entry_num ";
print "($remote_host - $remote_addr)<br>\n";
print "<input type=checkbox name=\"ban_host\" ";
print "value=\"$remote_host||$remote_addr\"> ";
print "Ban hostname and IP address from posting to feedback<p>\n";
}
elsif ($feedback_line =~ /<!--End Entry: $entry_num-->/) {
$entry_status = 0;
print "<hr size=7 width=75%>\n";
}
elsif ($entry_status == 1) {
print $feedback_line;
}
}
# Print submit buttons and end of page.
print "<center><input type=submit value=\"Remove Posts\"> ";
print "<input type=reset></center>\n";
print "</form>\n";
print "</body></html>\n";
}
############################################################################
# If the user has selected to Archive Posts from the main admin page, #
# print out the form to do so. #
############################################################################
elsif ($FORM{'type'} eq 'Archive Entries' && $FEEDBACK_FILE) {
# Localize variables used in this subroutine.
local($entry_num, $date, $remote_host, $remote_addr);
# Read in feedback lines.
open(FEEDBACK, $FEEDBACK_FILE)
|| &error('open->feedback_file', $FEEDBACK_FILE);
@feedback_lines = <FEEDBACK>;
close(FEEDBACK);
# Print page header and paragraph explaining this page's function.
&html_header('Feedback Admin: Archive Feedback Entries');
print "Check the checkboxes next to each entry if you wish to place\n";
print "it in the archive file specified in the \$MANUAL_ARCHIVE_FILE\n";
print "of your configuration file. This form also allows you to\n";
print "specify users you wish to ban from posting to the feedback.\n";
print "Simply check the checkbox next the the Ban this hostname and\n";
print "IP address and the hostnames and IP addresses shown in the ()\n";
print "on the line above will be banned from posting.<p>\n";
print "<form method=POST action=\"$ADMIN_CGI_URL\">\n";
print "<input type=hidden name=\"config_file\" ";
print "value=\"$FORM{'config_file'}\">\n";
print "<input type=hidden name=\"action\" value=\"$FORM{'type'}\">\n";
# If using username/password verifitcaion, print these form fields.
if ($USE_PASSWD eq 'YES') {
print "Username: <input type=text name=\"username\"><br>\n";
print "Password: <input type=password name=\"password\"><p>\n";
}
# Allow them to change the manual archive file on the fly or leave it
# as the default in their config file.
print "Manual Archive File: <input type=text name=\"manual_archive_file\" value=\"$MANUAL_ARCHIVE_FILE\" size=45><p>\n";
# Print separator for entries
print "<hr size=7>\n";
# Loop through feedback lines pulling out entries and creating the
# checkboxes and radio buttons for archiving.
foreach $feedback_line (@feedback_lines) {
if ($feedback_line =~ /<!--Begin Entry: (.*)\|\|(.*)\|\|(.*)\|\|(.*)-->/) {
$entry_num = $1;
$date = $2;
$remote_host = $3;
$remote_addr = $4;
$entry_status = 1;
print "<input type=checkbox name=\"$entry_num\" ";
print "value=\"archive\"> Archive Feedback Entry Number ";
print "$entry_num ($remote_host - $remote_addr)<br>\n";
print "<input type=checkbox name=\"ban_host\" ";
print "value=\"$remote_host||$remote_addr\"> ";
print "Ban hostname and IP address from posting to feedback<p>\n";
}
elsif ($feedback_line =~ /<!--End Entry: $entry_num-->/) {
$entry_status = 0;
print "<hr size=7 width=75%>\n";
}
elsif ($entry_status == 1) {
print $feedback_line;
}
}
# Print end of page and submit buttons.
print "<p><center><input type=submit value=\"Archive Posts\"> ";
print "<input type=reset></center>\n";
print "</form>\n";
print "</body></html>\n";
}
############################################################################
# If the user has selected to Change their username or password, print out #
# the form to do so. #
############################################################################
elsif ($FORM{'type'} eq 'Change Password' && $PASSWD_FILE) {
# Just a simple series of print's to get the password form out there.
&html_header('Feedback Admin: Change Password');
print "<form method=POST action=\"$ADMIN_CGI_URL\">\n";
print "<input type=hidden name=\"config_file\" ";
print "value=\"$FORM{'config_file'}\">\n";
print "<input type=hidden name=\"action\" value=\"$FORM{'type'}\">\n";
print "Old Username: <input type=text name=\"old_username\"><br>\n";
print "Old Password: <input type=password name=\"old_password\"><p>\n";
print "New Username: <input type=text name=\"new_username\"><br>\n";
print "New Password: <input type=password ";
print "name=\"new_password1\"><br>\n";
print "Re-Type New Password: ";
print "<input type=password name=\"new_password2\"><p>\n";
print "<p><center><input type=submit value=\"Change Password\"> ";
print "<input type=reset></center>\n";
print "</form>\n";
print "</body></html>\n";
}
############################################################################
# The action form field will be filled in if the user has completed a form #
# printed out in an earlier stage. In this case, the form is for #
# approving entries, and we will do so below. #
############################################################################
elsif ($FORM{'action'} eq 'Approve Entries') {
# If they are using username/password verification, check it.
if ($USE_PASSWD eq 'YES') {
&check_passwd;
}
# Open Approve file.
open(APPROVE, $APPROVE_FILE)
|| &error('open->approve_file', $APPROVE_FILE);
# Loop through each approve entry.
while ($approve_line = <APPROVE>) {
# Localize variables and give them their values.
local($entry_num, $date, $remote_host, $remote_addr, $form_string) = split(/\|\|/, $approve_line);
# Chop if there is a new line.
chop($form_string) if ($form_string =~ /\n$/);
# Undefine %CONFIG from last time through.
undef(%CONFIG);
# Define %CONFIG for this time through for use in templates.
&define_config($form_string);
# If this entry has been approved, write the feedback entry and
# push it onto an array for reporting back.
if ($FORM{$entry_num} eq 'approve') {
&write_feedback_entry($entry_num, $date, $remote_host, $remote_addr);
push(@approved, $entry_num);
# if any archiving of this is required automatcally, do so now.
if ($ARCHIVE_TYPE eq 'by_month') {
&archive_by_month;
}
elsif ($ARCHIVE_TYPE eq 'by_num' && $MAX_ENTRIES ne ''
&& $ARCHIVE_BY_NUM_FILE ne '') {
&archive_by_num;
}
}
# If the entry is to be held, push it onto a hold_approve array.
elsif ($FORM{$entry_num} eq 'hold') {
push(@hold_approve, $approve_line);
push(@held, $entry_num);
}
# Otherwise, don't do anything and it will just not be printed
# back.. Push it onto the @removed array for reporting back results.
else {
push(@removed, $entry_num);
}
}
close(APPROVE);
# Lock the approve file.
if (&lock($APPROVE_FILE, $LOCK_DIR, $MAX_WAIT)) {
&error($Error_Message);
}
# Open the file while we still have a lock and write any of the
# entries they asked to hold back into the approve file.
open (APPROVE, ">$APPROVE_FILE")
|| &error('write->approve_file', $APPROVE_FILE);
foreach $hold_line (@hold_approve) {
print APPROVE $hold_line;
}
# Unlock the file and close it again.
close(APPROVE);
&unlock($APPROVE_FILE, $LOCK_DIR);
# Print the successful result page and results.
&html_header('Feedback Admin: Posts Approved');
print "The following is a summary of the actions taken by Feedback\n";
print "Admin. The numbers represent the entry number. (A unique\n";
print "entry number is assigned to every post.\n";
print "<p><hr><p>\n";
print "<b>Approved:</b> ";
foreach $approved (@approved) {
print "$approved, ";
}
print "<p>\n<b>Removed:</b> ";
foreach $removed (@removed) {
print "$removed, ";
}
print "<p>\n<b>Held in Queue:</b> ";
foreach $held (@held) {
print "$held, ";
}
print "<p><hr><p>\n";
print "Return to <a href=\"$ADMIN_URL\">Feedback Admin</a>.\n";
print "</body></html>\n";
}
############################################################################
# The action form field will be filled in if the user has completed a form #
# printed out in an earlier stage. In this case, the form is for removing #
# entries, and we will do so below. #
############################################################################
elsif ($FORM{'action'} eq 'Remove Entries') {
# If they wish to use username/password verification, check it.
if ($USE_PASSWD eq 'YES') {
&check_passwd;
}
# Lock the feedback file.
if (&lock($FEEDBACK_FILE, $LOCK_DIR, $MAX_WAIT)) {
&error($Error_Message);
}
# Open feedback, read it in and get lock.
open(FEEDBACK, $FEEDBACK_FILE)
|| &error('open->feedback_file', $FEEDBACK_FILE);
@feedback_lines = <FEEDBACK>;
close(FEEDBACK);
# Open Feedback for writing.
open (FEEDBACK, ">$FEEDBACK_FILE")
|| &error('write->feedback_file', $FEEDBACK_FILE);
# For each line in the feedback file...
foreach $feedback_line (@feedback_lines) {
# If it begins an entry that is to be removed, , set the
# entry_status flag to 1 and don't print it back to the feedback.
if ($feedback_line =~ /<!--Begin Entry: (.*)\|\|.*\|\|.*\|\|.*-->/) {
$entry_num = $1;
if ($FORM{$entry_num} eq 'remove') {
$entry_status = 1;
}
else {
print FEEDBACK $feedback_line;
}
}
# Remove the end line and set the flag back to 0.
elsif ($feedback_line =~ /<!--End Entry: $entry_num-->/ && $entry_status == 1) {
$entry_status = 0;
}
# Print any other lines if the entry status is not 1.
elsif ($entry_status == 0) {
print FEEDBACK $feedback_line;
}
}
close(FEEDBACK);
&unlock($FEEDBACK_FILE, $LOCK_DIR);
# Print confirmation web page.
&html_header('Feedback Admin: Posts Removed');
print "The posts you requested to have removed have been.<p>\n";
print "Back to <a href=\"$ADMIN_URL\">Feedback Admin</a>.\n";
print "</body></html>";
}
############################################################################
# The action form field will be filled in if the user has completed a form #
# printed out in an earlier stage. In this case, the form is for #
# archiving entries, and we will do so below. #
############################################################################
elsif ($FORM{'action'} eq 'Archive Entries') {
# If they have username/password verification turned on, check it.
if ($USE_PASSWD eq 'YES') {
&check_passwd;
}
# Lock the feedback file so information read from the file will not
# change before we write it back.
if (&lock($FEEDBACK_FILE, $LOCK_DIR, $MAX_WAIT)) {
&error($Error_Message);
}
# Open and read in feedback file.
open(FEEDBACK, $FEEDBACK_FILE)
|| &error('open->feedback_file', $FEEDBACK_FILE);
@feedback_lines = <FEEDBACK>;
close(FEEDBACK);
# Lock the manual archive file.
if (&lock($FORM{'manual_archive_file'}, $LOCK_DIR, $MAX_WAIT)) {
&error($Error_Message);
}
# Open and read in the manual archive file.
open(ARCHIVE, "$FORM{'manual_archive_file'}")
|| &error('open->manual_archive_file', $FORM{'manual_archive_file'});
@archive_lines = <ARCHIVE>;
close(ARCHIVE);
# Open for writing the manual archive file.
open (ARCHIVE, ">$FORM{'manual_archive_file'}")
|| &error('write->manual_archive_file', $FORM{'manual_archive_file'});
# For each of the existing lines in the manual archive file...
foreach $archive_line (@archive_lines) {
# If this line is the begin marker, go through the feedback
# lines and archive any entries which were selected from the admin
# form. Anything that is not to be added to the archive file
# should be added to an array which will be re-written to the
# feedback file later.
if ($archive_line =~ /<!--begin-->/) {
if ($order_entry ne 'oldest->newest') {
print ARCHIVE "<!--begin-->\n";
}
foreach $feedback_line (@feedback_lines) {
if ($feedback_line =~ /<!--Begin Entry: (.*)\|\|.*\|\|.*\|\|.*-->/) {
$entry_num = $1;
if ($FORM{$entry_num} eq 'archive') {
$entry_status = 1;
print ARCHIVE $feedback_line;
}
else {
push(@keep_feedback_lines, $feedback_line);
}
}
elsif ($feedback_line =~ /<!--End Entry: $entry_num-->/
&& $entry_status ==1) {
$entry_status = 0;
print ARCHIVE $feedback_line;
}
elsif ($entry_status == 1) {
print ARCHIVE $feedback_line;
}
else {
push(@keep_feedback_lines, $feedback_line);
}
}
if ($order_entry eq 'oldest->newest') {
print ARCHIVE "<!--begin-->\n";
}
$begin_line = 1;
}
else {
print ARCHIVE $archive_line;
}
}
close(ARCHIVE);
&unlock($FORM{'manual_archive_file'}, $LOCK_DIR);
# If it can't find the begin marker in the manual_archive_file, it
# will throw an error.
if ($begin_line != 1) {
&error('begin_line', 'manual_archive_file');
}
# Open the feedback for writing.
open(FEEDBACK, ">$FEEDBACK_FILE")
|| &error('write->feedback_file', $FEEDBACK_FILE);
# For all of the feedback lines we shoul dkeep, write them back to
# the feedback.
foreach $keep_feedback_line (@keep_feedback_lines) {
print FEEDBACK $keep_feedback_line;
}
# Unlock the feedback and close it.
close(FEEDBACK);
&unlock($FEEDBACK_FILE, $LOCK_DIR);
# Print out a confirmation web page.
&html_header('Feedback Admin: Posts Archived');
print "The posts you requested to have archived have been.<p>\n";
print "Back to <a href=\"$ADMIN_URL\">Feedback Admin</a>.\n";
print "</body></html>";
}
############################################################################
# The action form field will be filled in if the user has completed a form #
# printed out in an earlier stage. In this case, the form is for changing #
# the admin's username and password. #
############################################################################
elsif ($FORM{'action'} eq 'Change Password') {
# Open the password file and obtain lock.
if (&lock($PASSWD_FILE, $LOCK_DIR, $MAX_WAIT)) {
&error($Error_Message);
}
open(PASSWD, $PASSWD_FILE) || &error('open->passwd_file', $PASSWD_FILE);
$old_password = <PASSWD>;
close(PASSWD);
# Chop any new lines off of the old username/password combination
if ($old_password =~ /\n$/) {
chop($old_password);
}
# Split username and password, localize
local($username, $old_passwd) = split(/:/, $old_password);
# If the encrypt flag is set, encrypt the old password and both new
# passwords from the form.
if ($ENCRYPT == 1) {
$FORM{'old_password'} = crypt($FORM{'old_password'}, substr($old_passwd, 0, 2));
$FORM{'new_password1'} = crypt($FORM{'new_password1'}, substr($old_passwd, 0, 2));
$FORM{'new_password2'} = crypt($FORM{'new_password2'}, substr($old_passwd, 0, 2));
}
# If the old password entered in the form doesn't match the old
# password in the file, throw an error.
if ($old_passwd ne $FORM{'old_password'}) {
&error('bad_password');
}
# If the old username entered in the form doesn't equal the old
# username from the file, throw an error.
if ($username ne $FORM{'old_username'}) {
&error('bad_password');
}
# If the new passwords (entered twice to make sure there was no
# mis-type), do not match, throw an error.
if ($FORM{'new_passwd1'} ne $FORM{'new_passwd2'}) {
&error('new_passwd_match');
}
# Open the password file for writing and write the new
# username/password combo.
open(PASSWD, ">$PASSWD_FILE")
|| &error('write->passwd_file', $PASSWD_FILE);
print PASSWD "$FORM{'new_username'}\:$FORM{'new_password1'}\n";
close(PASSWD);
&unlock($PASSWD_FILE, $LOCK_DIR);
# Print out a confirmation web page.
&html_header('Feedback Admin: Password Changed');
print "Your password and username have been changed.<p>\n";
print "<a href=\"$ADMIN_URL\">Back to Feedback Admin Main Page</a>\n";
print "</body></html>\n";
}
############################################################################
# If it doesn't fit above, then it is not a valid action. Send out an error#
############################################################################
else {
&error('bad_args');
}
# If banned hosts are checked in any of the forms, ban them now.
if ($FORM{'ban_host'}) {
# Get and localize the entry numbers from the ban_host form field.
local(@banned_hosts) = split(/,/, $FORM{'ban_host'});
# Lock the banned hosts file.
if (&lock($BANNED_HOSTS_FILE, $LOCK_DIR, $MAX_WAIT)) {
&error($Error_Message);
}
# Open banned hosts file for appending.
open(BANNED, ">>$BANNED_HOSTS_FILE")
|| &error('open->banned_hosts_file', $BANNED_HOSTS_FILE);
# Print out the new banned host record.
foreach $banned_host (@banned_hosts) {
$banned_host =~ s/\|\|/\,/;
print BANNED "$banned_host\n";
}
# Unlock and close the file.
close(BANNED);
&unlock($BANNED_HOSTS_FILE, $LOCK_DIR);
}
############################################################################
# Define a configuration array which can be used by the template parsing #
# routines. #
############################################################################
sub define_config {
# Localize variables.
local($name, $value, $pair, @pairs);
# Get pairs from the form string passed into this subroutine.
@pairs = split(/&/, $_[0]);
# For each of the pairs of information passed....
foreach $pair (@pairs) {
($name, $value) = split(/=/, $pair);
# Decode any & or = that were encoded so as not to mess up the
# parsing.
$name =~ s/--amp--/&/g;
$name =~ s/--eq--/=/g;
$value =~ s/--amp--/&/g;
$value =~ s/--eq--/=/g;
# Create a configuration field based on it so the templates can
# read this information when they are parsed.
if ($CONFIG{$name}) {
$CONFIG{$name} .= ",$value";
}
else {
$CONFIG{$name} = $value;
}
}
}
############################################################################
# Generate an HTML header for a specified title. #
############################################################################
sub html_header {
local($title) = $_[0];
print <<"END_HTML";
Content-type: text/html
<html>
<head>
<title>$title</title>
</head>
<body bgcolor=#FFFFFF text=#000000>
<center>
<h1>$title</h1>
</center>
END_HTML
}
############################################################################
# Write the feedback entry to the feedback file. #
############################################################################
sub write_feedback_entry {
# Localize incoming information and put it into variables.
local($num_entries, $date, $remote_host, $remote_addr) = @_;
# Lock the feedback file.
if (&lock($FEEDBACK_FILE, $LOCK_DIR, $MAX_WAIT)) {
&error($Error_Message);
}
# Open Feedback, read it in and lock it.
open(FEEDBACK, $FEEDBACK_FILE)
|| &error('open->feedback_file', $FEEDBACK_FILE);
@feedback_lines = <FEEDBACK>;
close(FEEDBACK);
# Open feedback for writing.
open(FEEDBACK, ">$FEEDBACK_FILE")
|| &error('write->feedback_file', $FEEDBACK_FILE);
# For each line, if it hits the begin marker, it will insert the new
# entry.
foreach $feedback_line (@feedback_lines) {
if ($feedback_line =~ /^<!--begin-->/) {
if ($ENTRY_ORDER ne 'oldest->newest') {
print FEEDBACK "<!--begin-->\n";
}
print FEEDBACK "<!--Begin Entry: $num_entries||$date||$remote_host||$remote_addr-->\n";
if (!&parse_template($FEEDBACK_TEMPLATE, *FEEDBACK)) {
&error('open->feedback_template', $FEEDBACK_TEMPLATE);
}
print FEEDBACK "<!--End Entry: $num_entries-->\n";
if ($ENTRY_ORDER eq 'oldest->newest') {
print FEEDBACK "<!--begin-->\n";
}
}
else {
print FEEDBACK $feedback_line;
}
}
# Unlock the feedback and close it.
close(FEEDBACK);
&unlock($FEEDBACK_FILE, $LOCK_DIR);
}
############################################################################
# If archiving by month is turned on, add the entry to the appropriate #
# month file. #
############################################################################
sub archive_by_month {
# Set the name of the archive file
@MON = ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep',
'Oct','Nov','Dec');
($mon, $year) = (localtime)[4, 5];
$year += 1900;
$month_archive_file = "$ARCHIVE_MONTH_DIR$MON[$mon]_$year.html";
# If the month archive file exists...
if (-e $month_archive_file) {
# Lock it, open it, read it in
if (&lock($month_archive_file, $LOCK_DIR, $MAX_WAIT)) {
&error($Error_Message);
}
open(MONTH_ARCHIVE, $month_archive_file)
|| &error('open->month_archive_file', $month_archive_file);
@month_archive_lines = <MONTH_ARCHIVE>;
close(MONTH_ARCHIVE);
# Open the month archive fle for writing. When we hit the begin
# marker, add the entry into this file as well
open(MONTH_ARCHIVE, ">$month_archive_file")
|| &error('write->month_archive_file', $month_archive_file);
foreach $month_archive_line (@month_archive_lines) {
if ($month_archive_line =~ /<!--begin-->/) {
if ($ENTRY_ORDER ne 'oldest->newest') {
print MONTH_ARCHIVE "<!--begin-->\n";
}
print MONTH_ARCHIVE "<!--Begin Entry: $num_entries||$date||$ENV{'REMOTE_HOST'}||$ENV{'REMOTE_ADDR'}-->\n";
if (!&parse_template($FEEDBACK_TEMPLATE, *MONTH_ARCHIVE)) {
&error('open->feedback_template', $FEEDBACK_TEMPLATE);
}
print MONTH_ARCHIVE "<!--End Entry: $num_entries-->\n";
if ($ENTRY_ORDER eq 'oldest->newest') {
print MONTH_ARCHIVE "<!--begin-->\n";
}
}
else {
print MONTH_ARCHIVE $month_archive_line;
}
}
close(MONTH_ARCHIVE);
&unlock($month_archive_file, $LOCK_DIR);
}
# Otherwise create a template file and call the subroutine again
else {
# Lock the month archive file.
if (&lock($month_archive_file, $LOCK_DIR, $MAX_WAIT)) {
&error($Error_Message);
}
open (MONTH_ARCHIVE, ">$month_archive_file")
|| &error('write->month_archive_file', $month_archive_file);
print MONTH_ARCHIVE <<END_MONTH_ARCHIVE;
<html>
<head>
<title>Monthly Feedback Archive: $months[$mon-1]/$year</title>
</head>
<body bgcolor=#FFFFFF text=#000000>
<center><h1>Feedback Archive: $months[$mon-1]/$year</h1></center>
Below is an archive of the feedback for $months[$mon-1]/$year.<p><hr><p>
<!--begin-->
<p><hr><p>
</body>
</html>
END_MONTH_ARCHIVE
close(MONTH_ARCHIVE);
&unlock($month_archive_file, $LOCK_DIR);
&archive_by_month;
}
}
############################################################################
# Otherwise, if it is archiving by number, check to see if the number #
# exceeds what is allowed, and if so archive entries by number. #
############################################################################
sub archive_by_num {
# For each line in the feedback (lines have already been read in
# from the script before.) if it begins an entry, push it onto the
# @entries array.
foreach $feedback_line (@feedback_lines) {
if ($feedback_line =~ /<!--Begin Entry: (.*)\|\|(.*)\|\|(.*)\|\|(.*)-->/) {
push(@entries, $1);
}
}
# Get the number of entries.
$num_entries = @entries;
# If the number of entries exceeds the maximum allowed entries,
# remove each entry one by one.
if ($num_entries >= $MAX_ENTRIES) {
$diff = ($num_entries - $MAX_ENTRIES);
$diff++;
for ($i = 1;$i <= $diff;$i++) {
if ($ENTRY_ORDER eq 'oldest->newest') {
$remove_entry = shift(@entries);
}
else {
$remove_entry = pop(@entries);
}
# Lock the feedback file.
if (&lock($FEEDBACK_FILE, $LOCK_DIR, $MAX_WAIT)) {
&error($Error_Message);
}
# Open the feedback, read in the new feedback_lines.
open(FEEDBACK, $FEEDBACK_FILE)
|| &error('open->feedback_file', $FEEDBACK_FILE);
@feedback_lines = <FEEDBACK>;
close(FEEDBACK);
# Write to the feedback, removing the remove_entry when we
# come to it.
open(FEEDBACK, ">$FEEDBACK_FILE")
|| &error('write->feedback_file', $FEEDBACK_FILE);
foreach $feedback_line (@feedback_lines) {
if ($feedback_line =~ /<!--Begin Entry: $remove_entry\|\|.*\|\|.*\|\|.*-->/) {
$archive_entry = $feedback_line;
$archive_flag = 1;
}
elsif ($feedback_line =~ /<!--End Entry: $remove_entry-->/) {
$archive_entry .= $feedback_line;
$archive_flag = 0;
}
elsif ($archive_flag == 1) {
$archive_entry .= $feedback_line;
}
else {
print FEEDBACK $feedback_line;
}
}
close(FEEDBACK);
&unlock($FEEDBACK_FILE, $LOCK_DIR);
# Lock the archive by num file.
if (&lock($ARCHIVE_BY_NUM_FILE, $LOCK_DIR, $MAX_WAIT)) {
&error($Error_Message);
}
# Open the archive by number file and try to obtain lock.
# Also read in all of the archive_lines.
open(ARCHIVE_BY_NUM, $ARCHIVE_BY_NUM_FILE)
|| &error('open->archive_by_num_file', $ARCHIVE_BY_NUM_FILE);
@archive_lines = <ARCHIVE_BY_NUM>;
close(ARCHIVE_BY_NUM);
# Open for writing the archive by number file.
open(ARCHIVE_BY_NUM, ">$ARCHIVE_BY_NUM_FILE")
|| &error('write->archive_by_num_file', $ARCHIVE_BY_NUM_FILE);
foreach $archive_line (@archive_lines) {
# Print the new entry if the begin marker is here.
if ($archive_line =~ /<!--begin-->/) {
if ($ENTRY_ORDER ne 'oldest->newest') {
print ARCHIVE_BY_NUM "<!--begin-->\n";
}
print ARCHIVE_BY_NUM $archive_entry;
if ($ENTRY_ORDER eq 'oldest->newest') {
print ARCHIVE_BY_NUM "<!--begin-->\n";
}
}
# Otherwise, just print the line.
else {
print ARCHIVE_BY_NUM $archive_line;
}
}
close(ARCHIVE_BY_NUM);
&unlock($ARCHIVE_BY_NUM_FILE, $LOCK_DIR);
}
}
}
############################################################################
# This checks the admin's username and password to make sure it is valid. #
############################################################################
sub check_passwd {
# Open the password file, get username and password and chop if there
# is a new line.
open(PASSWD, $PASSWD_FILE) || &error('open->passwd_file', $PASSWD_FILE);
($username, $password) = split(/:/, <PASSWD>);
chop($password) if ($password =~ /\n$/);
# Check for valid username and password if encrypt is turned on.
if (($ENCRYPT == 1 && (crypt($FORM{'password'}, substr($password, 0, 2)) ne $password))
|| $username ne $FORM{'username'}) {
&error('bad_password');
}
# Check for valid username and password if crypt is turned off.
elsif ($ENCRYPT != 1 && ($FORM{'password'} ne $password)
|| ($FORM{'username'} ne $username)) {
&error('bad_password');
}
}
############################################################################
# This is the Error subroutine. Should anything go wrong in the script #
# it will hopefully be caught and passed to this routine where it will #
# be printed to the screen and help may be offerred. #
############################################################################
sub error {
# Get and localize the error and optional file error occurred with.
($error, $file) = @_;
print "Content-type: text/html\n\n";
# If the config file is not available, supply an error and a link to
# the README fil if available.
if ($error eq 'config_file') {
&error_header('Feedback Admin Fatal Error: Config File Form Field Not Defined!');
print "The <tt>";
if ($README) {
print "<a href=\"$README#config_file\">config_file</a>\n";
}
else {
print "config_file";
}
print "</tt> form field was not defined. This field must contain\n";
print "the path to your feedback configuration file.\n";
&error_footer;
exit;
}
# If a bad password or username was entered supply the error
# explanation.
elsif ($error eq 'bad_password') {
&error_header('Feedback Admin Fatal Error: Bad Password or Username');
print "The username and password that you entered did not match\n";
print "the values listed in the \$PASSWD_FILE in your feedback\n";
print "configuration file. Please hit the back button on your\n";
print "browser and try again.<p>\n";
print "</body></html>\n";
}
# If the new passwords don't match, send out an error message
# explaining this.
elsif ($error eq 'new_passwd_match') {
&error_header('Feedback Admin Fatal Error: New Passwords Do Not Match');
print "The new passwords you just typed into the previous form\n";
print "do not match each other. Please return to the previous\n";
print "form and try again.<p>\n";
&error_footer;
}
# If there is no begin line in the manual archive file, send out an
# error explaining this.
elsif ($error eq 'begin_line') {
&error_header('Feedback Admin Fatal Error: No Begin Line');
if ($file eq 'manual_archive_file') {
print "There was no begin line in the Manual Archive File.\n";
print "Please check the file: $FORM{'manual_archive_file'}\n";
print "and make sure there is a line resembling:<pre>\n";
print "<!--begin-->\n";
print "</pre>\n";
}
&error_footer;
}
# If the script has a problem opening one of the files, send out a
# header with the exact problem, check to see if the file exists, and
# send out a message explaining what to do to correct this.
elsif ($error =~ /^open->(.*)/) {
if ($1 eq 'approve_file') {
&error_header('Feedback Admin Fatal Error: Approve File Unopenable');
}
elsif ($1 eq 'passwd_file') {
&error_header('Feedback Admin Fatal Error: Password File Unopenable');
}
elsif ($1 eq 'archive_by_num_file') {
&error_header('Feedback Admin Fatal Error: Archive By Number File Unopenable');
}
elsif ($1 eq 'feedback_file') {
&error_header('Feedback Admin Fatal Error: Feedback File Unopenable');
}
elsif ($1 eq 'month_archive_file') {
&error_header('Feedback Admin Fatal Error: Archive by Month File Unopenable');
}
elsif ($1 eq 'manual_archive_file') {
&error_header('Feedback Admin Fatal Error: Manual Archive File Unopenable');
}
print "The file: <b>$file</b> could not be opened for reading.<p>\n";
if (-e $file) {
print "The file does exist so please check to make sure you have\n";
print "correctly chmoded the file or made it readable by the\n";
print "web server. Type the following command at your Unix\n";
print "command line prompt:<pre>\n";
print " chmod 777 $file\n";
print "</pre>\n";
}
else {
print "The file does not exist. Check the value of the <tt>";
if ($README) {
print qq'<a href="$README#$1">\$$1</a>';
}
else {
print "\$$1";
}
print "</tt> variable to make sure you have correctly typed in\n";
print "the filename.\n";
}
&error_footer;
}
# If there is a file writing error, send out a header explaining
# which file it was, and then give proper chmod commands or tell the
# user that the file does not exist.
elsif ($error =~ /^write->(.*)/) {
if ($1 eq 'approve_file') {
&error_header('Feedback Admin Fatal Error: Approve File Not Writeable');
}
elsif ($1 eq 'passwd_file') {
&error_header('Feedback Admin Fatal Error: Password File Not Writeable');
}
elsif ($1 eq 'archive_by_num_file') {
&error_header('Feedback Admin Fatal Error: Archive by Number File Not Writeable');
}
elsif ($1 eq 'feedback_file') {
&error_header('Feedback Admin Fatal Error: Feedback File Not Writeable');
}
elsif ($1 eq 'month_archive_file') {
&error_header('Feedback Admin Fatal Error: Month Archive File Not Writeable');
}
elsif ($1 eq 'manual_archive_file') {
&error_header('Feedback Admin Fatal Error: Manual Archive File Not Writeable');
}
print "The file: <b>$file</b> could not be opened for writing.<p>\n";
if (-e $file) {
print "The file does exist so please check to make sure you\n";
print "have correctly chmoded the file or made it writeable\n";
print "by the web server. Type the following command into\n";
print "your Unix prompt:<pre>\n";
print " chmod 777 $file\n";
print "</pre>\n";
}
else {
print "The file does not exist. Check the value of the <tt>";
if ($README) {
print qq'<a href="$README#$1">\$$1</a>';
}
else {
print "\$$1";
}
print "</tt> variable to make sure you have correctly typed in\n";
print "the filename.\n";
}
&error_footer;
}
# If there were no form arguments specified, send out a message
# explaining this.
elsif ($error eq 'bad_args') {
&error_header('Feedback Admin Fatal Error: No Arguments!');
print "There were no arguments for the Feedback Admin script to\n";
print "work with. Please make sure you submit this form from the\n";
print "admin web page.\n";
&error_footer;
}
else {
&error_header($error);
&error_footer;
}
exit;
}
############################################################################
# This is useful for starting out an error message. It takes the #
# specified error title and turns that into the HTML title and header. #
############################################################################
sub error_header {
local($title) = $_[0];
print <<HTML_END;
<html>
<head>
<title>$title</title>
</head>
<body bgcolor=#FFFFFF text=#000000>
<center>
<h1>$title</h1>
</center>
HTML_END
}
############################################################################
# This ends the HTML page and links to the readme file on appropriate #
# pages and if available. #
############################################################################
sub error_footer {
if ($README) {
print "<p><hr><p>\n";
print "<ul>\n";
print "<li><a href=\"$README\">Feedback README (Installation and ";
print "Usage Intructions)</a>\n";
print "</ul>\n";
}
print " </body>\n";
print "</html>\n";
}