#!/usr/local/bin/webwork-perl ################################################################ # Copyright @1995-1999 by Michael E. Gage, Arnold K. Pizer and # WeBWorK at the University of Rochester. All rights reserved. ################################################################ my $debugON=0; ## set this to 1 to save debugging information for errors in hardcopy output use lib '.'; use webworkInit; # WeBWorKInitLine require 5.001; $/ ="\n"; use strict; use Global; use Auth; use CGI qw(:standard); use Net::SMTP; use Safe; use PGtranslator; #use sigtrap; BEGIN { # set to 1 to enable timing_log # (contains information about time taken by scripts to run) $main::logTimingData = 0; # begin Timing code if( $main::logTimingData == 1 ) { use Benchmark; $main::beginTime = new Benchmark; } # end Timing code # ## Setting these time out comstants to zeros removes the time constraint completely. (zero = infinity :=) ) $main::TIME_OUT_CONSTANT = 60; # one minute wait for on screen problems # $main::DOWNLOAD_TIME_OUT_CONSTANT = 300; # give it five minutes $main::CLASS_DOWNLOAD_TIME_OUT_CONSTANT = 1200; #twenty minutes # $main::DOWNLOAD_NICE = 2; $main::CLASS_DOWNLOAD_NICE = 5; # higher numbers indicated lower priorities # ## ATTENTION: The handlers PG_floating_point_exception_handler and PG_warnings_handler # ## have to be installed after CGI::Carp is called since it also # ## modifes the die and warn labels. Finding the right warning mechanism using these two # ## methods bears further investigation # ## They are defined in Global.pm $SIG{'FPE'} = \&Global::PG_floating_point_exception_handler; $SIG{__WARN__}=\&Global::PG_warnings_handler; $SIG{'TERM'} = sub {die '[',scalar(localtime),"] Caught a SIGTERM, Error: $! stopped at $0\n"; }; $SIG{'PIPE'} = sub {$main::SIGPIPE = 1, die '[',scalar(localtime),"] Caught a SIGPIPE, Error: $! stopped at $0\n"; }; $SIG{ALRM} = sub { $main::SIG_TIME_OUT = 1; exit(0) }; alarm($main::TIME_OUT_CONSTANT); # By explicitly catching the signals and dieing one forces the execution of the END statements which clean up the files. # }; use vars qw ($modules_to_evaluate $extra_packages_to_be_loaded ); &CGI::ReadParse; my %inputs=%main::in; my $query = $main::in{CGI}; # verify that the rest of the information has been received my $Course = $inputs{'course'}; my $User = $inputs{'user'}; #my $psvn = $inputs{'probSetKey'}; my @local_psvns = $query -> param('local_psvns'); my $psvn = $local_psvns[0]; ## get the first one for doing problem sets $inputs{'probSetKey'} = $psvn; ## only used by htmlBOTTOM my $Session_key = $inputs{'key'}; &Global::getCourseEnvironment($Course); my $scriptDirectory = getWebworkScriptDirectory(); #$Global::scriptDirectory; my $databaseDirectory = getCourseDatabaseDirectory(); #$Global::databaseDirectory; my $courseScriptsDirectory = getCourseScriptsDirectory(); #$Global::courseScriptsDirectory; my $templateDirectory = getCourseTemplateDirectory(); #$Global::templateDirectory; # this is globally defined for the file, since it is needed for cleanup in END my $tempDirectory = getCourseTempDirectory(); eval{require "${courseScriptsDirectory}$Global::displayMacros_pl";} ; eval{require "${scriptDirectory}$Global::DBglue_pl";}; eval{require "${scriptDirectory}$Global::classlist_DBglue_pl";}; eval{require "${scriptDirectory}$Global::HTMLglue_pl";}; eval{require "${scriptDirectory}$Global::FILE_pl";} ; #################################################################### # load the modules to be used in PGtranslator require "${courseScriptsDirectory}PG_module_list.pl" or wwerror($0, "Can't read ${courseScriptsDirectory}PG_module_list.pl"); #################################################################### my $keyFile = &Global::getCourseKeyFile($Course); my $permissionsFile = &getCoursePermissionsFile($Course); ## check to see if prob set has been selected ## verifyInput(); ############################################## sub verifyInput { if(!defined($psvn) || $psvn eq "") { &selectionError; # The calling script did not specify a problem set. #die "Content-type: text/html\n\nThe calling script did not specify a problem set."; exit(); } } # log access &Global::log_info('', query_string); &verify_key($inputs{'user'}, $Session_key, $keyFile, $Course); my $permissions = &get_permissions($User,$permissionsFile); &attachProbSetRecord($psvn); my $login_name_for_psvn = &getStudentLogin($psvn); attachCLRecord($login_name_for_psvn); my $setNumber=&getSetNumber($psvn); $setNumber = $inputs{'setNo'} if defined $inputs{'setNo'}; ## script called from profChangeDates.pl # keep strict happy my $tempTexFileBaseName; ###### check to see that it is after the open date my ($currentTime,$odts,$ddts,$remainingTime, $TimeString); $currentTime = time; $odts=&getOpenDate($psvn); $ddts=&getDueDate($psvn); $remainingTime=$ddts-$currentTime; if($currentTime<$odts && $permissions !=$Global::instructor_permissions) { print &htmlTOP("Before open date error"); print "
| Select one of the $numberOfProblems problems to try: ENDOFHTML print " |
ENDOFHTML
## process problem and save @printlines
my $probHeader = $Global::PROB_HEADER; # default value
if ( (defined($probHeaderFileName)) and ($probHeaderFileName =~ /\S/)) {
$probHeader = $probHeaderFileName;
}
## use $probHeader as default unless $probHeaderFileName is defined
## in the set definition file
my $source;
if (-e "${templateDirectory}$probHeader" ) {
unless (-r "${templateDirectory}$probHeader") {
wwerror($0, "Can't read ${templateDirectory}$probHeader");
}
open(PROB,"<${templateDirectory}$probHeader");
$source = join("", |
/\\par\n/ig;
$warnings =~ s/\#/\\\#/g; #protect against some of the symbols which are reserved in tex
$warnings =~ s/\_/\\\_/g;
$warnings =~ s/\>/\\\>/g;
$warnings =~ s/\\\\/dev/null") && warn "Could not renice process. pid $$";
alarm( $main::CLASS_DOWNLOAD_TIME_OUT_CONSTANT);
my $downloadMulti = "unknown";
$downloadMulti = "multistudent" if $action eq "Get_all_copies";
$downloadMulti = "multiset" if $action eq "Get_hard_copy";
my @psvns_to_download = $query->param('local_psvns');
my $num_psvns_to_download = @psvns_to_download;
my $max_psvns_to_download = $Global::max_num_of_ps_downloads_allowed;
if($num_psvns_to_download > 1 and $permissions != $Global::instructor_permissions) {
wwerror("Non-professors are not permitted to download more than one problem set at a time.");
}
if(@psvns_to_download > $Global::max_num_of_ps_downloads_allowed) {
my $tooManyWhat = $downloadMulti eq "multiset" ? "problem sets" : "students";
wwerror("Too many $tooManyWhat are selected for download.",
"The maximum number of $tooManyWhat which can be downloaded at one time is $Global::max_num_of_ps_downloads_allowed."
." You selected $num_psvns_to_download. Go back and select fewer $tooManyWhat."
." (This maximun is set by the variable \$max_num_of_ps_downloads_allowed in Global.pm.)");
}
my ($cumulativeTexSource, $currentTexSourceRef, $currentTexSource, $currentTexErrorRef);
# this could be used when eliminating pre-foreach createTexSourceHandleErrors call
# s/\\end\{document\}.*?\\begin\{document\}/\n\\newpage\n/s;
$tempTexFileBaseName = "${tempDirectory}Temp_downloadAllSets_$User";
my $first_psvn = $psvns_to_download[0];
my $current_psvn = shift @psvns_to_download;
($currentTexSourceRef, $currentTexErrorRef) = createTexSource($current_psvn);
@psvns_to_download = () if(@$currentTexErrorRef);
$currentTexSource = $$currentTexSourceRef;
$currentTexSource =~ s|\\end\{document\}\s$|\n|s;
$cumulativeTexSource .= $currentTexSource;
foreach $current_psvn (@psvns_to_download) {
($currentTexSourceRef, $currentTexErrorRef) = createTexSource($current_psvn);
@psvns_to_download = () if(@$currentTexErrorRef);
$currentTexSource = $$currentTexSourceRef;
$currentTexSource =~ s|^.*?\\begin\{document\}|\n\\newpage\n|s;
$currentTexSource =~ s|\\end\{document\}\s$|\n|s;
$cumulativeTexSource .= $currentTexSource;
}
$cumulativeTexSource .= "\n\\end{document}\n";
open TEXOUTPUT, ">$tempTexFileBaseName.tex"
or wwerror("Can't open $tempTexFileBaseName.tex for output.");
print TEXOUTPUT $cumulativeTexSource;
close TEXOUTPUT;
if(@$currentTexErrorRef) {
PG_error_print($tempTexFileBaseName, $current_psvn, @$currentTexErrorRef);
} else {
$downloadType = lc $downloadType;
my $mimeType = prepareHardcopy($tempTexFileBaseName, $downloadType);
my ($setName, $userName);
&attachProbSetRecord($first_psvn);
if($downloadMulti eq "multistudent") {
if($num_psvns_to_download == 1) {
$setName = getSetNumber($first_psvn);
$userName = getStudentLogin($first_psvn);
} else {
$setName = getSetNumber($first_psvn);
$userName = "multistudent";
}
} elsif($downloadMulti eq "multiset") {
if($num_psvns_to_download == 1) {
$setName = getSetNumber($first_psvn);
$userName = getStudentLogin($first_psvn);
} else {
$setName = "multiset";
$userName = getStudentLogin($first_psvn);
}
}
my $hardCopyName = "$Course.$userName.$setName.$downloadType";
open(TEXINPUT, "$tempTexFileBaseName.$downloadType")
or wwerror($0, "Can't open $tempTexFileBaseName.$downloadType: $!\n");
print "Content-type: $mimeType\n";
print "Content-disposition: attachment; filename=\"$hardCopyName\"\n\n";
print while ( Unable to open TeX source file:
ENDhtmlTOP
$out;
}
sub probSet_titleBar {
my ($title) = @_;
my $title_bar = "";
$title_bar .= qq{
",
&sessionKeyInputs(\%inputs),
hidden(-name=>'local_psvns', -value=>$psvn),
hidden(-name=>'action', -value=>'Do_problem_set'),
submit(-value=>"Return to Problem Set"),
endform(),
&htmlBOTTOM($0, \%inputs);
}
sub defineProblemEnvir {
my ($mode,$probNum,$psvn,$courseName,$refSubmittedAnswers) = @_;
my %envir=();
my $loginName = &getStudentLogin($psvn);
##how to put an array submittedAnswers in a hash??
$envir{'refSubmittedAnswers'} = $refSubmittedAnswers if defined($refSubmittedAnswers);
$envir{'psvnNumber'} = $psvn;
$envir{'psvn'} = $psvn;
$envir{'studentName'} = &CL_getStudentName($loginName);
$envir{'studentLogin'} = $loginName;
$envir{'sectionName'} = &CL_getClassSection($loginName);
$envir{'sectionNumber'} = &CL_getClassSection($loginName);
$envir{'recitationName'} = &CL_getClassRecitation($loginName);
$envir{'recitationNumber'} = &CL_getClassRecitation($loginName);
$envir{'setNumber'} = &getSetNumber($psvn);
$envir{'questionNumber'} = $probNum;
$envir{'probNum'} = $probNum;
$envir{'openDate'} = &getOpenDate($psvn);
$envir{'formatedOpenDate'} = &formatDateAndTime(&getOpenDate($psvn));
$envir{'formattedOpenDate'} = &formatDateAndTime(&getOpenDate($psvn));
$envir{'dueDate'} = &getDueDate($psvn);
$envir{'formatedDueDate'} = &formatDateAndTime(&getDueDate($psvn));
$envir{'formattedDueDate'} = &formatDateAndTime(&getDueDate($psvn));
$envir{'answerDate'} = &getAnswerDate($psvn);
$envir{'formatedAnswerDate'} = &formatDateAndTime(&getAnswerDate($psvn));
$envir{'formattedAnswerDate'} = &formatDateAndTime(&getAnswerDate($psvn));
$envir{'problemValue'} = &getProblemValue($probNum,$psvn);
$envir{'fileName'} = &getProblemFileName($probNum,$psvn);
$envir{'probFileName'} = &getProblemFileName($probNum,$psvn);
$envir{'languageMode'} = $mode;
$envir{'displayMode'} = $mode;
$envir{'outputMode'} = $mode;
$envir{'courseName'} = $courseName;
$envir{'sessionKey'} = ( defined($inputs{'key'}) ) ?$inputs{'key'} : " ";
# initialize constants for PGanswermacros.pl
$envir{'numRelPercentTolDefault'} = getNumRelPercentTolDefault();
$envir{'numZeroLevelDefault'} = getNumZeroLevelDefault();
$envir{'numZeroLevelTolDefault'} = getNumZeroLevelTolDefault();
$envir{'numAbsTolDefault'} = getNumAbsTolDefault();
$envir{'numFormatDefault'} = getNumFormatDefault();
$envir{'functRelPercentTolDefault'} = getFunctRelPercentTolDefault();
$envir{'functZeroLevelDefault'} = getFunctZeroLevelDefault();
$envir{'functZeroLevelTolDefault'} = getFunctZeroLevelTolDefault();
$envir{'functAbsTolDefault'} = getFunctAbsTolDefault();
$envir{'functNumOfPoints'} = getFunctNumOfPoints();
$envir{'functVarDefault'} = getFunctVarDefault();
$envir{'functLLimitDefault'} = getFunctLLimitDefault();
$envir{'functULimitDefault'} = getFunctULimitDefault();
$envir{'functMaxConstantOfIntegration'} = getFunctMaxConstantOfIntegration();
$envir{'numOfAttempts'} = undef(); # this is defined only for problems
# defining directorys and URLs
$envir{'templateDirectory'} = &getCourseTemplateDirectory();
$envir{'classDirectory'} = $Global::classDirectory;
$envir{'cgiDirectory'} = $Global::cgiDirectory;
$envir{'macroDirectory'} = getCourseMacroDirectory();
$envir{'courseScriptsDirectory'} = getCourseScriptsDirectory();
$envir{'htmlDirectory'} = getCourseHtmlDirectory();
$envir{'htmlURL'} = getCourseHtmlURL();
$envir{'tempDirectory'} = getCourseTempDirectory();
$envir{'tempURL'} = getCourseTempURL();
$envir{'scriptDirectory'} = $Global::scriptDirectory;
$envir{'webworkDocsURL'} = $Global::webworkDocsURL;
$envir{'externalTTHPath'} = $Global::externalTTHPath;
$envir{'inputs_ref'} = \%inputs;
my $seed = &getProblemSeed($probNum, $psvn);
$seed = 1111 unless defined($seed);
$envir{'problemSeed'} = $seed if defined($seed);
# here is a way to pass environment variables defined in webworkCourse.ph
my $k;
foreach $k (keys %Global::PG_environment ) {
$envir{$k} = $Global::PG_environment{$k};
}
%envir;
}
BEGIN {
# This subroutine cleans up temporary files after the postscript copy has been created.
#
sub cleanup_downloadPS {
unless (defined($action ) and ($action eq 'Do problem set' or $action eq 'Do_problem_set')) {
my $ERRORS = $save_errors;
unless ($debugON) { #clean up the directory
eval {
chdir $tempDirectory;
unlink(
"#tempTexFileBaseName.dvi",
"$tempTexFileBaseName.ps",
"$tempTexFileBaseName.pdf",
"$tempTexFileBaseName.log",
"$tempTexFileBaseName.aux",
"$tempTexFileBaseName.tex"
);
unlink("${tempDirectory}eps/${login_name_for_psvn}*.eps");
}; # clean up
$ERRORS .= $ERRORS . $@;
}
my $query = query_string();
$query = "" unless defined($query);
wwerror("$0", "ERROR: in downloadPS subroutine of welcomeAction.pl $ERRORS","","",$query) if $ERRORS;
}
}
}
END {
if (defined($main::SIG_TIME_OUT) && $main::SIG_TIME_OUT == 1) {
alarm(0); # turn off the alarm
my $hard_copy_message = qq{Content-type: text/html\n\n
\n
Use the back button to return to the previous page and try again.
Because the WeBWorK server at the Unversity of Rochester is experiencing heavy use we have made downloading
hard copies a low priority during the times of very heavy useage. It will be helpful if you
download hard copies during times when the load is not too heavy.
The load is usually heaviest in the evenings , particularly a few hours before assignments
are due. The best times to download hard copies are in the morning and afternoon
-- or an hour after the due date and time of the previous assignment -- nobody is using the system then :-)
\n
You should be warned that WeBWorK response will be unusually slow. If possible you should try
to use WeBWorK at another time when the load is not as high. The highest useage periods are in the
evening, particularly in the two hours before assignments are due. \n
Use the back button to return to the previous page and try again. \n
If the high useage problem continues you can report this to your instructor using the feedback button.
PG error while compiling problem number", (@errors>1) ? 's ' : ' ',
join(', ', @errors), " in problem set $setName for $userName.
";
print "TeX source file:
";
# open temp tex file
if(open TEXINPUT, "$tempTexFileBaseName.tex") {
print "\n";
my $lineNumber = 1;
while(
$tempTexFileBaseName.texCan't open log file:
path= $texFileBaseName.log
$!
" ;
print "TeX Error Log:
";
my $print_error_switch = ($debugON) ? 1: 0;
my $out='';
#warn ord $/, ord "\n", ord "\r";
#warn "length of separator = ", length($/);
$/ = "\n";
#warn ord $/, ord "\n", ord "\r";
while (
\n" if $print_error_switch;
}
close(LOGFILE);
open (TEXFILE, "$texFileBaseName.tex")
|| print "Can't open tex source file:
path= $texFileBaseName.tex:
$!
\n";
print "
\nTeX Source File:
\n";
print "";
my $lineNumber = 1;
while (";
print &htmlBOTTOM("welcomeAction.pl", \%inputs);
}
sub protect_HTML {
my $line = shift;
chomp($line);
$line =~s/\&/&/g;
$line =~s/</g;
$line =~s/>/>/g;
$line;
}
sub selectionError {
print &htmlTOP("Selection error");
print"Error:
You must first select a problem set in order to download a hard copy!\n";
print "
ENDOFHTML
print &htmlBOTTOM("welcomeAction.pl", \%inputs);
}
sub probSet_htmlTOP {
my ($title, $bg_url) = @_;
my $background_url = $bg_url || $Global::background_plain_url;
my $out = <
};
$title_bar;
}
sub hackerError { ## prints hacker error message
my $msg = "Attempt to hack into WeBWorK \n Remote Host is: ". remote_host()."\n";
$msg .= query_string;
&Global::log_error('hacker error', $msg); ## log attempt
## notify by email
my $toAdd = $Global::feedbackAddress;
my $emailMsg = "To: $toAdd
Subject: Attempt to hack into WeBWorK
Here are the details on the attempt to hack into weBWorK:\n
$msg
\n";
my $smtp = Net::SMTP->new($Global::smtpServer, Timeout=>20);
$smtp->mail($Global::webmaster);
$smtp->recipient($Global::feedbackAddress);
$smtp->data($msg);
$smtp->quit;
# my $SENDMAIL = $Global::SENDMAIL;
# open (MAIL,"|$SENDMAIL");
# print MAIL "$emailMsg";
# close (MAIL);
print &htmlTOP("Hacker Error"),
"
$title
Error:Please do not try to hack into WeBWorK!
",
startform(-action=>"${Global::cgiWebworkURL}${Global::welcomeAction_CGI}"),
"
};
my $do_problem_message = qq{Content-type: text/html\n\n
WeBWorK hard copy download time out.
\n
This download was cancelled because it took more than $main::TIME_OUT_CONSTANT seconds.
This may be because the
WeBWorK server is extraordinarily busy, or because there was an error in the problem,
or because you tried to download a set with too many problems (more than 50).
\n
If the problem is repeated you can report this to your instructor using the feedback button.
};
if ($action eq 'Get hard copy' or $action eq 'Get_hard_copy') {
print $hard_copy_message;
} else{
print $do_problem_message;
}
}
# begin Timing code
if( $main::logTimingData == 1 ) {
my $endTime = new Benchmark;
my $error_str='';
if ($main::SIGPIPE) {
$error_str = 'broken PIPE--';
}
elsif ($main::SIG_TIME_OUT) {
$error_str = "TIME_OUT after $main::TIME_OUT_CONSTANT secs --";
}
elsif ($action eq 'Get hard copy' or $action eq 'Get_hard_copy') {
$error_str = 'successful download -- ';
}
&Global::logTimingInfo($main::beginTime,$endTime,$error_str.'welcomeAction.pl',$Course,$User);
}
# end Timing code
cleanup_downloadPS();
}
1;
WeBWorK heavy useage time out.
\n
Your request (action = $action) was cancelled because it took more than $main::TIME_OUT_CONSTANT seconds.
This is probably because the
WeBWorK server is extraordinarily busy.