Pipes | Streams  «Prev 

Using Web Mail Form in Perl

email.cgi

#!/usr/bin/perl
# email.cgi
# (c) 1997 Bill Weinman
# a simple email form for the Web
#

$CRLF = "\x0d\x0a";
$user_agent  = $ENV{HTTP_USER_AGENT};
$remote_host = $ENV{REMOTE_HOST};
$remote_addr = $ENV{REMOTE_ADDR};
$servername  = $ENV{SERVER_NAME};  # this server
$scriptname  = $ENV{REDIRECT_URL} || $ENV{SCRIPT_NAME};  # this program's URI
$callback = "http://$servername$scriptname";  # how to call back
$sendmail = "/usr/lib/sendmail";
$switches = " -t -f webmaster\@$servername";
$mailto   = "Bill Weinman <testuser\@luna.bearnet.com>";
$xmagic   = "Magic Mailer 1.0";

print "Content-type: text/html$CRLF$CRLF";

# get the query vars, if any
%query = getquery();

# if there's no data, assume this is the first iteration
$state = 'first' unless %query;

# prevent users from entering 
# arbitrary HTML in thier entries
while(($qname, $qvalue) = each %query) {
  # convert any HTML entities
  $qvalue =~ s/</<\;/g;
  $qvalue =~ s/>/>\;/g;
  $qvalue =~ s/"/"\;/g; 
  $$qname = $qvalue; 
  }
$referer = $ENV{HTTP_REFERER} unless $referer;

# what now is
$date = localtime;

# the main jump table
if    ($state eq 'first') { first()    }
elsif ($state eq 'send' ) { mailvalid() }
elsif ($state eq 'edit' ) { mailedit() }
elsif ($state eq 'sent' ) { mailsent() }
else { unknown() }

exit;


# STATE SCREENS

sub first{
htmlhead("My Email");
htmlp("first.htmlp");
htmlfoot();
}

sub mailvalid{
$disp_message = $message;
$disp_message =~ s/\r\n/\n/g;       # fold the cr/lf pairs
$disp_message =~ s/\n{2}/<p>\n/g;   # format it for the screen

return error("'$email' is not a valid email address")
  unless ($email =~ /^[a-z][\w-.+]*\@[\w-]*[.][\w-.]*$/);

htmlhead("Sending Email");
htmlp("valid.htmlp");
htmlfoot();
}

sub mailedit{
htmlhead("My Email: Edit the Message");
htmlp("edit.htmlp");
htmlfoot();
}

sub mailsent{
if ($oops) { mailedit }
else {
  mailsend() or return 0;
  htmlhead("Email Sent");
  htmlp("sent.htmlp");
  htmlfoot();
  }
}

sub error{
local $error = shift;

htmlhead("My Email: $state");
htmlp("error.htmlp");
htmlfoot();
return 0;
}

sub unknown{
htmlhead("My Email: unknown state: $state");
print "<h1>Unknown state!</h1>\n";
printvars();
htmlfoot();
}

# COMMON HTML HEADER AND FOOTER
# htmlhead(title)
# print the top of the html file
#
sub htmlhead{
 local $title = shift;
 htmlp("header.htmlp");
}

# htmlfoot
# print the foot of the html file
#
sub htmlfoot{
 my $title = shift;
 htmlp("footer.htmlp");
}
# EMAIL ROUTINES
sub mailsend{
 return error(qq(cannot find $sendmail)) unless (-x $sendmail);
 open(MAIL, "| $sendmail $switches") or
  return error(qq(cannot open "$sendmail $switches": $!));
 print MAIL <<SENDMAIL;
 X-Mailer: $xmagic [$referer]
 To: $mailto
 From: $name <$email>
 Subject: [$subject]
 Referer:     [$referer]
 Remote Host: [$remote_host]
 Remote Addr: [$remote_addr]
 User Agent:  [$user_agent]
 $message
 ---
 This message was sent by $xmagic
 SENDMAIL
 close MAIL;
}

# UTILITY ROUTINES
# getquery
# returns hash of CGI query strings
sub getquery{
my $method = $ENV{'REQUEST_METHOD'};
my ($query_string, $pair);
my %query_hash;
$query_string = $ENV{'QUERY_STRING'} if $method eq 'GET';
$query_string = <STDIN> if $method eq 'POST';
return undef unless $query_string;
foreach $pair (split(/&/, $query_string)) {
  $pair =~ s/\+/ /g;
  $pair =~ s/%([\da-f]{2})/pack('c',hex($1))/ieg;
  ($_qsname, $_qsvalue) = split(/=/, $pair);
  $query_hash{$_qsname} = $_qsvalue;
  }
 return %query_hash;
}

# printvars # diagnostic to print the environment and CGI variables sub printvars{ print "<p>Environment:<br>\n"; foreach $e (sort keys %ENV) { print "<br><tt>$e => $ENV{$e}</tt>\n"; } print "<p>Form Vars:<br>\n"; foreach $name (sort keys %query) { print "<br><tt>$name => [$query{$name}]</tt>\n"; } } # htmlp # generic print an html file routine # file may also contain: # $variable for a perl variable # $$filename for a nested file # for arbitrary perl code # sub htmlp{ local $filename = shift; # this code has to be reentrant to make file includes work # so we need a uniqe filehandle for each file opened (since # more than one may be open at once). # just strip all the nonalphas from the filename for the # filehandle my $fhstring = $filename; $fhstring =~ s/[^a-z]//i; unless (-f $filename) { print qq(<h1>Error: </h1>\n); print qq(<p><em>htmlp</em> can't find "$filename"</p>\n); return ""; } open($fhstring, "<$filename"); while(<$fhstring>) { # comment this out if you think it's too dangerous # to execute perl code s/$\{(.*?)}/eval($1),""/eg; # $$filename to include another file s/$$([\S;]+;?)/htmlp($1)/eg; # $variable to include a variable s/$(\w+)//eg; print; } close $fhstring; return ""; }