#!/usr/bin/env perl # $Id$ # feedback.pl: Mail feedback to a specified user, with the URL of the # referring page automagically included. Reject bogus # destination addresses. # # Usage: invoke as http://site/cgi-bin/feedback.pl?address1,address2,... use lib '.'; use webworkInit; # WeBWorKInitLine use Global; use CGI qw(:standard); use CGI::Carp qw(fatalsToBrowser); use HTML::Entities (); use Net::SMTP; $ENV{'PATH'} = ''; # try to avoid PATH attacks # log access &Global::log_info('', query_string); my $Course = param('course'); # establish environment for this script &Global::getCourseEnvironment($Course) if defined $Course; # local configuration stuff $BGCOLOR = '#ffffff'; $LOGFILE = &Global::getWebworkLogsDirectory() . "webwork-feedback.log"; # if path = '/send' we're processing a filled-out form my $ADDR; # define 'globally' so that it can be used by subroutines if (path_info() eq '/send') { # Bad destinations shouldn't make it this far, since we already checked # for bad "To:" when generating the feedback form. However, it's still # possible that some evildoer has submitted a bogus form, so we check # again... foreach $ADDR (split(/\s*,\s*/, param('To'))) { &check_destination($ADDR); &user_error('You didn\'t enter any comments.') if (param('comments') eq ''); &user_error('You didn\'t enter an e-mail address.') unless (param('email') =~/\@/); my $smtp = Net::SMTP->new($Global::smtpServer, Timeout=>10) || &internal_error("Couldn't contact SMTP server."); $smtp->mail($Global::smtpSender); if ( $smtp->recipient($ADDR)) { # this one's okay, keep going $smtp->data(&output(0,$ADDR) . access_link($ADDR) ) || &internal_error("Unknown problem sending message data to SMTP server."); } else { # we have a problem with this address $smtp->reset; &internal_error("SMTP server doesn't like this address: <$ADDR>."); } $smtp->quit; &log("Mail sent to: " . $ADDR . " from: " .param('email') ); } # &log("Mail sent to: " . param('To') . " from: " .param('email') ); &thank_you; } else { # No path info: we're generating a form to be filled-out $To = $ENV{'QUERY_STRING'}; $To = $Global::webmaster if ($To eq ''); &check_destination($To); &generate_form; } exit(0); ############################## Subroutines ################################# sub internal_error { my $msg = join " ", @_; &log("ERROR: $msg"); print header, start_html('-title' => "Internal Error", -bgcolor=>"$BGCOLOR"), h1('Internal Error'), b(HTML::Entities::encode($msg)), p, "Your message could not be sent. Please notify ", "<", a({href=>"mailto:$Global::webmaster"}, $Global::webmaster), ">. ", br, "We apologize for the inconvenience.", end_html; exit(1); } sub user_error { my $msg = join " ", @_; print header, start_html('-title' => 'User error', -BGCOLOR=>"$BGCOLOR"), h1('User error'), p, b(HTML::Entities::encode($msg)), p, "Please hit the "Back" button on your browser to ", "try again, or notify ", br, "<", a({href=>"mailto:$Global::webmaster"}, $Global::webmaster), "> ", "if you believe this message is in error.", end_html; exit(1); } sub check_destination { my($address_list) = @_; my (@address) = split(/\+*,\+*/, $address_list); for (@address) { &internal_error("Sorry, I'm not allowed to send mail to <$_>.") if !/$Global::legalAddress/; } } #http://webwork.math.rochester.edu/cgi-bin/development/processProblem7.pl?probSetKey=51823&probNum=7&Mode=HTML_tth&course=mth161dev&user=gage&key=NQ18Kry70j*.8Lsok3ulG^QHAp3zRG0hjHE5emT4 sub access_link { my $ADDR = shift; my $url = param('referring_url'); $USER = $ADDR; #param('To'); $USER =~s/@.*$//; # determine the user (the recipient of this message) from the mail message. This method may change. $url =~ s/\?.*$//; my $warning_limit = $^W; $^W=0; $url .= '?probSetKey='.param('probSetKey').'&probNum='.param('probNum').'&Mode='.param('Mode').'&show_old_answers=1'.'&course='.param('course')."&user=$USER&key=".param('key'); $^W= $warning_limit; return ("-------\nTo go directly to the student's page, click on the Access Link and enter your password under Fast relogin.\nAccess Link " . $url . "\n"); } sub log { my $msg = $_[0]; # open(LOGFILE, ">> $LOGFILE") || &internal_error("Can't write to $LOGFILE"); # warn("Can't write to $LOGFILE\n"); open(LOGFILE, ">> $LOGFILE") || warn("Can't write to $LOGFILE\n"); ## above line leads to an infinite loop print LOGFILE 'Date: ', scalar(localtime), "\n"; print LOGFILE $msg; print LOGFILE "\n------\n"; close(LOGFILE); } sub thank_you { print header, start_html( '-title'=>'Thank You', -BGCOLOR=>"$BGCOLOR"), h1('Your message has been mailed.'), "To: ", param('To'), '


',&output(0,param('To') ),'
', end_html; } sub generate_form { my $list = "," . $To; $list =~ s/,/
  • /g; my $from = param('email'); $from = ' ' unless defined $from; print header, start_html('-title'=>'WeBWorK - Feedback', -bgcolor=>"$BGCOLOR"), img({align=>'LEFT', alt=>"", src=>$Global::headerImgUrl}), p({align=>'right'}), br({clear=>'ALL'}), hr, h1('WeBWorK Feedback Gateway'), start_form('POST', url() . '/send'), hidden('To', $To), hidden('name'), hidden('id'), hidden('referring_url', referer()), hidden('probSetKey'), hidden('setnum'), hidden('probNum'), hidden('course'), hidden('section'), hidden('recitation'), hidden('Mode'), hidden('user'), hidden('key'), strong("To: "), kbd($To), br, strong("From: "), param('name'), br, p, textfield(-name=>'email',-default => $from, -size=>'32',-override=>1), ' ', b('E-mail'), i(' (must be filled in!)'),br, p, b('Your comments:'), ' ', i('(must be filled in!)'), br, textarea('comments', '', 15, 70), p, b(submit('submit', 'Submit Your Comments')), end_form, end_html; } sub output { my $suppress_output = $_[0]; my $addr = $_[1]; my $msg; my $replyTo = param('email'); $replyTo .= ', ' . $Global::defaultReply if ($Global::defaultReply =~ /\w/); $msg = # message header "From: " . param('email') . " (" . param('name') . ")\n" . "To: " . $addr . "\n" . "Reply-To: " . $replyTo . "\n" . "X-Remote-Host: " . remote_host . " (" . remote_addr . ")\n" . "Subject: WeBWorK Feedback from " . param('course'). "/" . param('user'). "\n" . "\n" . # message body: student data "User: " . param('user') . "\n" . "Name: " . param('name') . "\n" . "Student ID: " . param('id') . "\n" . "Course: " . param('course') . "\n" . "Section: " . param('section') . "\n" . "Recitation: " . param('recitation') . "\n" . "PSVN: " . param('probSetKey') . "\n" . "Set number: " . param('setnum') . "\n" . "Problem number: " . param('probNum') . "\n" . "Mode: " . param('Mode') . "\n" . "Key: " . param('key') . "\n" . # "DataMunger URL: $munger" . "\n" . "\n"; # for logs: don't log actual message, just student info return $msg if $suppress_output; # message body: message $msg .= "Allegedly from: " . param('email') . "\n" . "Comments:\n-------\n" . param('comments') . "\n"; return $msg; }