#!/usr/local/bin/perl ############################################################################## # Postcard.cgi Free version! Bewley Internet Solutions my $VERSION='Postcard.cgi v1.0b6'; #03-11-97 #----------------------------------------------------------------------------- # This script and others found at http://www.bewley.net/perl/ # # BETA VERSION # Yet to be cleaned up into final form, but seems to work well. # # This is a free version of the BIS Postcard.cgi. It uses a flat file # pseudo database to store the cards. A pay version is forthcoming # which will have more features and a database backend. Either dbm or mysql. # # INSTALLATION INSTRUCTIONS. # # 1. This program requires you to have CGI.pm installed on your system. # See: http://www-genome.wi.mit.edu/ftp/pub/software/WWW/#installation # # 2. Make sure the line at the top points to perl on your system. # You might find out if you type "which perl" on the UNIX command line. # # 3. Edit the user configurable variables near the top of the script. # # 4. Ask your ISP where you can run CGI from. Sometimes you must call it # through a wrapper and locate it in a cgi-bin directory. Sometimes it # is sufficient to give it a name ending in .cgi. This is the case on # bewley.net. Install as they direct. # # 5. Make sure the CGI has write permission to $DATA_FILE. If you use a # wrapper it will. If not you may have to make the file and directory # containing it to world writable. Ask your ISP for help. # # 6. Create your index page. Sample at: # http://www.bewley.net/postcard/ # # Todo: # o Add option to remove card when viewed, overriding $CARD_LIFE. # # o Add a feature that will automatically create the thumbmail index # so you can just drop postcard.cgi into a dir of graphics and fly. # # o Create a dbm version. # # o Add template support for postcard output. # # o Clean up. # # # Copyright (C) 1997 Dale Bewley, Bewley Internet Solutions # # This program 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 2 # 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, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # ############################################################################## #- User Configurable Variables ----------------------------------------------# # experimenting right now. broken... # # Change these values to fit your site. # # full URL to postcard homepage my $BASE_REF = 'http://www.bewley.net/postcard/'; # Number of days to keep card around before removing it. my $CARD_LIFE = 7; # full path to postcard data file. The program will create this file. my $DATA_FILE = '/httpd/htdocs/bewley/postcard/postcard.dat'; # full or relative URL location of images my $IMG_URL = '/photos/'; # this is the return address users get their postcard notice from. my $MAIL_FROM = 'postcard@bewley.net'; # most likely this is correct my $MAIL_PROG = '/usr/lib/sendmail -i -t'; # full URL to pickup postcard. "?code=____" will be added automatically. my $PICKUP_URL = 'http://bewley.net/postcard/postcard.cgi'; # subject of email notifications my $SUBJECT = 'Bewley.net Postcard for you!'; # location of thumbnails relative to images. This is unused right now. my $THUMB_DIR = 'thumbs/'; # That's it! # # # #- End User Config ----------------------------------------------------------# #- Main Program -------------------------------------------------------------# # uncoment following display errors to the browser for debugging help # BEGIN { # use CGI::Carp qw(carpout); # carpout(STDOUT); # } use CGI; # This will put more useful information in your error_log use CGI::Carp; my $create_time = time(); $FORM = new CGI; if ($FORM->param('code')) { print $FORM->header; (&selectCard($FORM->param('code')) && &displayCard) || &console; print "

Send your own postcard to someone!

"; } elsif (! $FORM->param('rcpt')) { print $FORM->header; &solicitMsg; } else { &makeCard; ¬ifyRcpt; print $FORM->redirect($PICKUP_URL . "?code=$create_time" . $FORM->param('rcpt')); } # please leave these 3 lines intact! print "\n "; print "$VERSION\n by Bewley Internet "; print "Solutions.\n"; print $FORM->end_html; # if sub selectCard discovers an expired card it gets put on @death_row if (@death_row) { &executeCards(@death_row); } #- End Main Program ----------------------------------------------------------# sub solicitMsg { # Ask what they want on their tombstone... I mean postcard! print $FORM->start_html(-title=>'Fill in your postcard.', -author=>'dale@bewley.net', -BGCOLOR=>"#ffffff"); # this will be filled if user forgets to supply a To: email $photo = $FORM->param('img'); # otherwise... if (! $photo) { # filename comes in like this # big.jpg.x=23&big.jpg.y=122 so pull it from input # since we don't know the image filename, we don't know # the field name, so search them all @fields = $FORM->param(); foreach $field (@fields) { if ($field =~ s/\.x$//) { $photo = $field; } } } print "

Please fill in your postcard.

\n\n"; print $FORM->startform(-method=>'POST'); print "
\n\n"; print "\n\n
\n"; print "
\n"; print "
Email To:\n
"; print $FORM->textfield(-name=>'rcpt'); print "\n
Email From:\n
"; print $FORM->textfield(-name=>'from'), "

\n"; print "

Message:\n
"; print $FORM->textarea(-name=>'msg', -rows=>10, -cols=>30); print "
\n", $FORM->submit, "
\n"; print "
\n"; print "
"; print ""; print $FORM->hidden(-name=>'img', -value=>$photo), "
\n"; print "
\n"; print "
\n
"; print $FORM->endform; print "\n\n"; } sub makeCard { # Write card to DATA_FILE my $msg = $FORM->param('msg'); # URL encode the message $msg =~ s/(\W)/ sprintf("%%%02x",ord($1))/eg; $FORM->param('msg',$msg); open (FH, ">>$DATA_FILE") || die "Can't open $DATA_FILE for write. $!"; # code, recipient, sender, image, message. print FH $create_time, "\0"; print FH $FORM->param('rcpt'), "\0"; print FH $FORM->param('from'), "\0"; print FH $FORM->param('img'), "\0"; print FH $FORM->param('msg'), "\n"; close FH; } sub notifyRcpt { # Let the recipient know they have a postcard waiting. open(MAIL, "|$MAIL_PROG") || die "Can't open $MAIL_PROG. $!"; print MAIL "From: ", $MAIL_FROM, "\n"; print MAIL "To: ", $FORM->param('rcpt'), "\n"; print MAIL "Subject: $SUBJECT\n\n"; print MAIL "Greetings!\n\nSomeone has filled out a postcard in your "; print MAIL "name!\n\nYou have $CARD_LIFE days to pick it up from:\n"; print MAIL " $PICKUP_URL?code=$create_time" . $FORM->param('rcpt'); print MAIL "\n\nYour postcard pal,\n $MAIL_FROM\n\n"; close MAIL; } sub selectCard { # given a code, find the realcode in DATA_FILE # real pickup code is $create_time . rcpt my $check_code = shift; # something like 87531122dale@bewley.net my $apocolypse = $create_time - (86400 * $CARD_LIFE); open (FH, "<$DATA_FILE") || die $!; while () { # check for expired cards here ($realcode,$rcpt) = split(/\0/,$_,2); if ($realcode < $apocolypse) { push(@death_row, $realcode); } # might this be a match? Most likely. if ($check_code =~ /^$realcode/) { ($realcode,$rcpt,$from,$img,$msg) = split(/\0/); ($sec, $min, $hour, $mday, $mon, $year) = localtime($check_code); $date = sprintf ("%02s/%02d/%02d %02d:%02d:%02d", ++$mon, $mday, $year, $hour, $min, $sec); #$date = ++$mon ."/$mday/$year $hour:$min:$sec"; $msg =~ s/%([0-9a-fA-F]{2})/pack("c",hex($1))/ge; $realcode .= $rcpt; if ($check_code eq $realcode) { return 1; } # bingo! } } return 0; } sub displayCard { # later add support to pull in a template here instead of hard code print $FORM->start_html(-title=>'Here is your postcard. Thank you!', -author=>'dale@bewley.net', -BGCOLOR=>"#ffffff"); print "

Your Postcard:

\n\n"; print "
\n\n"; print "\n\n
\n"; print "From: $from
\n"; print "To: $rcpt
\n"; print "Date: $date

\n"; print "

Message:

\n"; print "
$msg
\n"; print "
\n"; print "
\n"; print "
\n
"; } sub console { print $FORM->start_html(-title=>'Sorry!', -author=>'dale@bewley.net', -BGCOLOR=>"#ffffff"); print "

Sorry!

Either your code is invalid "; print "or your card has expired.

\n"; } sub executeCards { # remove expired cards from data file my @death_row = @_; open(OLD, "<$DATA_FILE") || die "Can't open $DATA_FILE input. $!"; &lockFile(OLD); open(NEW, ">$DATA_FILE.tmp") || die "Can't open $DATA_FILE.tmp ouput. $!"; &lockFile(NEW); my $good_as_dead = join('|',@death_row); my $soul; while ($soul = ) { print NEW $soul unless ($soul =~ /^$good_as_dead/o); } close OLD; close NEW; &unlockFile(NEW); rename("$DATA_FILE.tmp","$DATA_FILE") || die "Can't rename $DATA_FILE.tmp to $DATA_FILE. $!"; &unlockFile(OLD); } sub lockFile { local($FH) = @_; local($try) = 0; local($status) = 0; while ($status != 0) { $status = flock($FH, 2); ($try == 4) && last; $status && sleep(1); $try++; } } sub unlockFile { local($FH) = @_; flock($FH, 8); }