#!/usr/local/bin/perl5 -w # # FillInForm # # Fill in a form and re-present the results. # # This is a simple program which takes the results of # a form, and presents the form again with all of the # fields filled in as specified. This allows the page # to be printed. # # You can optionally have the form fields checked for # some sort of validity (Perl regular expressions), and # if the form isn't valid, present the form again with # messages. # # Finally, when the form is complete, you can specify an # email address to send the form variables to, or some # other form completion CGI program. # # Dave Regan # regan@peak.org # http://cornvalley.peak.org/FillInForm # 23 September 1997 # # # Ideas from Bob Richardson : # # 1. Substitutions # # (Or can this be done already using FIF-RE?) - The ability to predefine a # substitution that is done on a form field. This would allow, for # example, removal of control characters (tab, newline, etc.) from # TEXTAREA fields. # # 2. Negative Regular Expression (FIF-NRE?) # # Cause an error if the regular expression returns a match. This would # allow a form to search for keywords that should NOT be included, and # notify the user. Applications include stripping potential foul language # to searching for common mistakes like putting "www." in what should be # an email address, or "@" in what should be a URL. # # 3. Multi-Stage Input Collection # # For longer forms, it is sometimes better for the user to break things up # into stages, and then combine it all into one email at the end. For # example, and "order form" could start off with name/address/phone, then # proceed to a page of item #'s, and then finally to a method of payment # page. Or can this be achieved already by using hidden fields and doing # the right things with the .FIF files? # # 4. Conditional URL branching # # This could be done in the .FIF (for security reasons) - based on the # value of a field, select which URL comes next. # # # Things that don't work # ---------------------- # # The code for ### ### ### ### Due to abuse considerations, the From and Reply-To fields are ### the only mail header fields that can be set in the form. ### ### In addition, variables of the form: ### FIF-* ### are used in different ways to control FillInForm, and are ### not sent to the user. ### ### All other variables are alphabetized by symbol name and sent ### to the user, and presented on the screen. ### ### Note that there is no checking that any of the email addresses ### look reasonable. ### sub SendEmail { my($cmd) = @_; my($addr, $hdr, $key, $reply); $addr = $Vars{'Mail-To'}; Error("$0: No value defined for Mail-To\n") if (!defined($addr)); DisplayFinalPage("FillInForm sends email", "FillInForm has sent email to $addr"); # Send mail to the intended recipient. OpenMail(); # Use all of the "Mail-*" variables as mail headers. for $key (@Names) { next unless ($key =~ /^Mail-(.*)/); $hdr = $1; print MAIL "$hdr: $Vars{$key}\n"; $reply = $Vars{$key} if ($hdr =~ /^from$/i && !defined($reply)); $reply = "" if ($hdr =~ /^reply-to$/); } print MAIL "Reply-To: $reply\n" if (defined($reply) && $reply ne ""); print MAIL "\n"; # Separate headers from body FormatReport(); close MAIL; exit 0; } ### ### SendLog ### ### Send the results to the named file or directory named by FIF-LogName. ### If the name is a directory, create a unique name. ### ### The variables of the form Mail-* and FIF-* are not sent ### through by default. ### sub SendLog { my($cmd) = @_; my($addr, $count); $addr = $Vars{'FIF-LogName'}; Error("$0: No value defined for FIF-LogName\n") if (!defined($addr)); if (-d $addr) { for ($count = 0; -f "$addr/$count"; $count++) { } $addr = "$addr/$count"; } Error("$0: Cannot open $addr") if (!open(MAIL, ">>$addr")); flock(MAIL, 2); seek(MAIL, 0, 2); DisplayFinalPage("FillInForm logs data", "FillInForm has logged to $addr"); FormatReport(); close MAIL; exit 0; } ### ### SubVariables ### ### Introduce all of the variables into place. ### sub SubVariables { my($text) = @_; my($class, $name, $sym, %user, $user, $val); # Substitute all of the variables in for $name (keys %Vars) { $sym = "\\\$$name\\\$"; $val = $Vars{$name}; # $val =~ s/"/\"/g; $text =~ s/$sym/$val/g; } if (defined($QW)) { while ($text =~ /QW\s*\((.*)\)/) { ($name, $sym) = split(/\s*,\s*/, $1, 2); # print STDERR "QW with $name and $sym\n"; ($class, $user) = GlobalVars(); # user not used %user = GetUser($class, $name); # Take the specified user $text =~ s/QW\s*\((.*)\)/$user{$sym}/; } } return $text; } ### ### UnEntity ### ### Massage a string so that it will print. ### sub UnEntity { my($text) = @_; $text =~ s/&/&/g; $text =~ s//>/g; return $text; } ### ### unquote ### ### Unescape a CGI form variable. ### sub unquote { my($raw) = @_; my($code, @pieces, $piece); $raw =~ s/\+/ /mg; @pieces = split(/%/, $raw); for ($piece = 1; $piece <= $#pieces; $piece++) { $pieces[$piece] =~ s/^%//; $code = substr($pieces[$piece], 0, 2); $code = hex($code); $pieces[$piece] = sprintf("%c%s", $code, substr($pieces[$piece], 2)); } return join("", @pieces); } ### ### ValidateName ### ### Ensure that the filename is reasonable. ### sub ValidateName { my($fname, $type) = @_; Error("$0: Cannot find $fname\n") if (! -f $fname); Error("$0: Filename $fname does not end in $type") if ($fname !~ /$type$/); return $fname; } ### ### WebName ### ### Given a filename, turn it into a file name for reading. ### sub WebName { my($fname) = @_; my($dir, $tail); 1 while $fname =~ s#/\.\./#/#g; 1 while $fname =~ s#^../##g; $fname =~ s#^/+##; if ($fname =~ m#^~([^/]+)(.*)#) { $fname = $2; $dir = (getpwnam($1))[7]; Error("$0: Cannot find home directory for $1") if (!defined($dir)); $fname = "$dir/public_html/$fname"; } else { $fname = "$ENV{'DOCUMENT_ROOT'}/$fname"; } return $fname; }