#!/usr/bin/perl
#
# Send is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
# $Id: send,v 1.16 2009/12/23 00:04:08 suter Exp $
# [MJS 17 Oct 2002] Simple and safe web form for /contacts/
# [MJS 21 Sep 2009] Added Authen::Captcha and cleaned up a little
use strict;
use warnings;
use CGI::Simple;
use Template;
use Authen::Captcha;
use HTML::Entities;
use MIME::Base64;
## Initialize our template and variables
my $template = Template->new( { INCLUDE_PATH => '/home/suter/web/zwitterion.org:/var/www/zwitterion.org/', EVAL_PERL => 1 } );
my %vars = (
## Fixed variables used in the templates
admin => 'webmaster@zwitterion.org',
admin_name => 'Zwitterion Webmaster',
destination => 'suter@zwitterion.org',
destination_name => 'Mark Suter',
data_folder => '/tmp/.zwitterion-captcha-db',
output_folder => '/var/www/zwitterion.org/contacts/captchas',
## Defaults from the form (regex to detect unchanged submissions)
from => qr/^example $/,
subject => qr/^I do not spam$/,
message => qr/^Your source.+will be displayed\.$/ms,
);
## To allow indented HERE documents for improved code readability
sub fix {
local $_ = shift;
s/^\s{4}//gm;
return $_;
}
eval {
## Initialize CGI object and start output
my $q = new CGI::Simple;
print $q->header( -pragma => 'no-cache', -expires => '-1d' );
-e $vars{data_folder} or mkdir $vars{data_folder} or die "$vars{data_folder} doesn't exist!\n";
-e $vars{output_folder} or mkdir $vars{output_folder} or die "$vars{output_folder} doesn't exist!\n";
## Ready our captcha engine
my $captcha = Authen::Captcha->new(
data_folder => $vars{data_folder},
output_folder => $vars{output_folder},
width => 30,
height => 40
) or die;
## Promote any encoded versions
foreach (qw(from subject message)) {
if ( defined( $q->param("base64_$_") ) ) {
$q->param($_, decode_base64( $q->param("base64_$_") ) );
}
}
## Get clean versions of our parameters
my $count = 0;
foreach (qw(from subject message)) {
if ( defined( $q->param($_) ) ) {
if ( $q->param($_) =~ $vars{$_} ) {
$vars{$_} = 'default value';
}
else {
$vars{$_} = $q->param($_);
## Ok, now clean-up the value safely
$vars{$_} =~ s{[^[:space:][:print:]]+}{}gix;
## Record the count (zero is bad)
$count++;
}
}
else {
$vars{$_} = 'not submitted';
}
}
die "No real values given!\n" unless $count > 0;
## Create the encoded versions
foreach (qw(from subject message)) {
$vars{"base64_$_"} = encode_base64( $vars{$_} );
}
## Include the source address to help track abuse.
my $source_address = q{};
foreach (qw(HTTP_USER_AGENT REMOTE_ADDR HTTP_X_FORWARDED_FOR HTTP_VIA)) {
exists( $ENV{$_} ) or next;
my $label = '_' . lc $_;
$label =~ s/_(.)/'-' . uc $1/ge;
$source_address .= "X$label: $ENV{$_}\n";
}
$source_address .= "\n";
## Construct a plain text message to email
$vars{email} = fix <<" EOF" ; ## NB: four spaces
From: $vars{admin_name} <$vars{admin}>
To: $vars{destination_name} <$vars{destination}>
Subject: Message from http://zwitterion.org/contacts/
$source_address
The following details are based on information submitted
to the webform at http://zwitterion.org/contacts/
From: $vars{from}
Subject: $vars{subject}
$vars{message}
EOF
## Encode the message for presentation to the customer
$vars{encoded} = HTML::Entities::encode( $vars{email} );
## Captcha passed?
my $results = 0;
if ( $q->param('code') and $q->param('md5sum') ) {
## Carefully get the captcha parameters
my $md5sum = $q->param('md5sum');
my $code = $q->param('code');
$md5sum =~ s{ \A ( [0-9a-z]+ ) \Z }{$1}ix or die "regex: $md5sum\n";
$code =~ s{ \A ( [0-9a-z]+ ) \Z }{$1}ix or die "regex: $code\n";
## Carefully check the captcha
$results = $captcha->check_code( $code, $md5sum );
}
if ( $results == 1 ) {
## Send the email
$ENV{PATH} = '/bin:/usr/bin';
open MAIL, "| /usr/sbin/sendmail -oi -oem -t -f $vars{admin}"
or die "There was a problem forking the mailer!\n";
print MAIL $vars{email}, "\n";
close MAIL or die "There was a problem with sending the mail.\n";
## Output success
$template->process( 'contacts/success', \%vars );
}
else {
## Offer the Captcha
( $vars{md5sum}, $vars{code} ) = $captcha->generate_code(5);
$vars{image} = '/contacts/captchas/' . $vars{md5sum} . '.png';
$template->process( 'contacts/captcha', \%vars );
}
};
if ($@) {
$vars{error} = $@;
$template->process( 'contacts/failure', \%vars );
}