Parent Directory
|
Revision Log
Added logPrint to error messages when the TeX code cannot be converted into a .dvi file. This allows useful feedback when there is a pure tex error -- i.e. the .pg file compiles correctly but the resulting TeX is not well formed. Also added some code that adds warning messages after each problem (except the screen/pageheader file) with some extra formatting so that messages can be handled by the TeX processor. If this latter code is adequate it should probably be abstracted and moved to Global near where the PG warnings handler is defined. Currently the code modifies the Global::WARNINGS variable VERY far away from the definition of that variable. It would be better to have a couple of subroutines in Global that "print" the WARNINGS string, perhaps protecting the characters that upset TeX, and another subroutine which clears the WARNINGS variable. Meantime keep testing the error output -- it's looking better.
1 #!/usr/local/bin/webwork-perl 2 3 4 ################################################################ 5 # Copyright @1995-1999 by Michael E. Gage, Arnold K. Pizer and 6 # WeBWorK at the University of Rochester. All rights reserved. 7 ################################################################ 8 9 my $debugON=0; ## set this to 1 to save debugging information for errors in hardcopy output 10 11 use lib '.'; use webworkInit; # WeBWorKInitLine 12 require 5.001; 13 14 $/ ="\n"; 15 16 use strict; 17 use Global; 18 use Auth; 19 use CGI qw(:standard); 20 use Net::SMTP; 21 use Safe; 22 23 24 use PGtranslator; 25 #use sigtrap; 26 BEGIN { 27 # set to 1 to enable timing_log 28 # (contains information about time taken by scripts to run) 29 $main::logTimingData = 0; 30 31 # begin Timing code 32 if( $main::logTimingData == 1 ) { 33 use Benchmark; 34 $main::beginTime = new Benchmark; 35 } 36 # end Timing code 37 38 # ## Setting these time out comstants to zeros removes the time constraint completely. (zero = infinity :=) ) 39 $main::TIME_OUT_CONSTANT = 60; # one minute wait for on screen problems 40 # $main::DOWNLOAD_TIME_OUT_CONSTANT = 300; # give it five minutes 41 $main::CLASS_DOWNLOAD_TIME_OUT_CONSTANT = 1200; #twenty minutes 42 # $main::DOWNLOAD_NICE = 2; 43 $main::CLASS_DOWNLOAD_NICE = 5; # higher numbers indicated lower priorities 44 45 # ## ATTENTION: The handlers PG_floating_point_exception_handler and PG_warnings_handler 46 # ## have to be installed after CGI::Carp is called since it also 47 # ## modifes the die and warn labels. Finding the right warning mechanism using these two 48 # ## methods bears further investigation 49 # ## They are defined in Global.pm 50 $SIG{'FPE'} = \&Global::PG_floating_point_exception_handler; 51 $SIG{__WARN__}=\&Global::PG_warnings_handler; 52 $SIG{'TERM'} = sub {die '[',scalar(localtime),"] Caught a SIGTERM, Error: $! stopped at $0\n"; }; 53 $SIG{'PIPE'} = sub {$main::SIGPIPE = 1, die '[',scalar(localtime),"] Caught a SIGPIPE, Error: $! stopped at $0\n"; }; 54 $SIG{ALRM} = sub { $main::SIG_TIME_OUT = 1; exit(0) }; 55 56 alarm($main::TIME_OUT_CONSTANT); 57 # By explicitly catching the signals and dieing one forces the execution of the END statements which clean up the files. 58 # 59 }; 60 61 use vars qw ($modules_to_evaluate $extra_packages_to_be_loaded 62 ); 63 64 &CGI::ReadParse; 65 my %inputs=%main::in; 66 67 my $query = $main::in{CGI}; 68 69 # verify that the rest of the information has been received 70 my $Course = $inputs{'course'}; 71 my $User = $inputs{'user'}; 72 73 #my $psvn = $inputs{'probSetKey'}; 74 75 my @local_psvns = $query -> param('local_psvns'); 76 my $psvn = $local_psvns[0]; ## get the first one for doing problem sets 77 $inputs{'probSetKey'} = $psvn; ## only used by htmlBOTTOM 78 my $Session_key = $inputs{'key'}; 79 80 81 &Global::getCourseEnvironment($Course); 82 83 my $scriptDirectory = getWebworkScriptDirectory(); #$Global::scriptDirectory; 84 my $databaseDirectory = getCourseDatabaseDirectory(); #$Global::databaseDirectory; 85 my $courseScriptsDirectory = getCourseScriptsDirectory(); #$Global::courseScriptsDirectory; 86 my $templateDirectory = getCourseTemplateDirectory(); #$Global::templateDirectory; 87 88 # this is globally defined for the file, since it is needed for cleanup in END 89 my $tempDirectory = getCourseTempDirectory(); 90 91 eval{require "${courseScriptsDirectory}$Global::displayMacros_pl";} ; 92 eval{require "${scriptDirectory}$Global::DBglue_pl";}; 93 eval{require "${scriptDirectory}$Global::classlist_DBglue_pl";}; 94 eval{require "${scriptDirectory}$Global::HTMLglue_pl";}; 95 eval{require "${scriptDirectory}$Global::FILE_pl";} ; 96 97 98 99 #################################################################### 100 # load the modules to be used in PGtranslator 101 102 require "${courseScriptsDirectory}PG_module_list.pl" or 103 wwerror($0, "Can't read ${courseScriptsDirectory}PG_module_list.pl"); 104 #################################################################### 105 106 my $keyFile = &Global::getCourseKeyFile($Course); 107 my $permissionsFile = &getCoursePermissionsFile($Course); 108 109 ## check to see if prob set has been selected ## 110 verifyInput(); 111 112 ############################################## 113 sub verifyInput { 114 115 if(!defined($psvn) || $psvn eq "") { 116 &selectionError; # The calling script did not specify a problem set. 117 #die "Content-type: text/html\n\nThe calling script did not specify a problem set."; 118 exit(); 119 } 120 } 121 122 # log access 123 &Global::log_info('', query_string); 124 125 126 &verify_key($inputs{'user'}, $Session_key, $keyFile, $Course); 127 128 my $permissions = &get_permissions($User,$permissionsFile); 129 130 &attachProbSetRecord($psvn); 131 my $login_name_for_psvn = &getStudentLogin($psvn); 132 attachCLRecord($login_name_for_psvn); 133 134 my $setNumber=&getSetNumber($psvn); 135 $setNumber = $inputs{'setNo'} if defined $inputs{'setNo'}; ## script called from profChangeDates.pl 136 137 # keep strict happy 138 my $tempTexFileBaseName; 139 140 ###### check to see that it is after the open date 141 my ($currentTime,$odts,$ddts,$remainingTime, $TimeString); 142 $currentTime = time; 143 $odts=&getOpenDate($psvn); 144 $ddts=&getDueDate($psvn); 145 $remainingTime=$ddts-$currentTime; 146 147 if($currentTime<$odts && $permissions !=$Global::instructor_permissions) { 148 print &htmlTOP("Before open date error"); 149 print "<CENTER><h2>Sorry, cannot download or do problem set $setNumber yet. 150 <BR>It is before the open date.</h2></CENTER>"; 151 print &htmlBOTTOM("downloadPS.pl",\%inputs); 152 exit(0); 153 } 154 155 my %PSVNHashForSet = %{getPSVNHashForSet($setNumber)}; 156 my $action = $inputs{'action'}; 157 my $downloadType= $inputs{'downloadType'}; # either pdf, ps, tex, or dvi 158 159 # Verify that the problem set has been created if a psvn number has been passed 160 unless ($action eq 'Get_all_copies') { 161 unless (defined $PSVNHashForSet{$psvn} ) { 162 print &htmlTOP("Problem set version number $psvn not created"); 163 print ( "Pin number $psvn was not created for set $setNumber"); 164 print &htmlBOTTOM("downloadPS.pl", \%inputs); 165 exit(0); 166 } 167 } 168 169 my $texFile = "${login_name_for_psvn}.tempTex-CGIscript"; 170 my $save_errors=''; 171 172 if ($action eq 'Do problem set' or $action eq 'Do_problem_set') {displayProbSet();} 173 #elsif ($action eq 'Get hard copy' or $action eq 'Get_hard_copy') {downloadIndividualSet();} 174 elsif ($action eq 'Get hard copy' or $action eq 'Get_hard_copy') {downloadAllSets();} 175 elsif ($action eq 'Get_all_copies') {downloadAllSets();} 176 else {wwerror($0, "Unknown action: $action");} 177 178 179 # begin Timing code 180 # my $endTime = new Benchmark; 181 # &Global::logTimingInfo($main::beginTime,$endTime,$0,$Course,$User); 182 # end Timing code 183 184 exit; 185 ############################################# 186 187 sub displayProbSet { 188 my $studentName=&CL_getStudentName($login_name_for_psvn); 189 my $probHeaderFileName = &getProbHeaderFileName($psvn); 190 191 my @problems=sort numerical &getAllProblemsForProbSetRecord($psvn); 192 sub numerical { $a <=> $b}; 193 194 my $numberOfProblems=0; 195 my $prob; 196 foreach $prob (@problems) {$numberOfProblems++;} 197 198 199 print &probSet_htmlTOP("Problem Set $setNumber from $inputs{'course'} for $studentName"); 200 #see subroutines at the bottom of this file 201 #this allows the use of a small gif for the webwork logo 202 #and takes up less screen real estate. 203 204 print &probSet_titleBar("Problem Set $setNumber from $inputs{'course'} for $studentName"); 205 206 print <<"ENDOFHTML"; 207 <TABLE BORDER=1> 208 <TR> 209 <!-- Row 1 Column 1 --> 210 <TD> 211 212 Select one of the $numberOfProblems problems to try: 213 <FORM METHOD=POST ACTION="$Global::processProblem_CGI"> 214 <INPUT TYPE=HIDDEN NAME=probSetKey VALUE=$psvn> 215 <P> 216 <SELECT NAME=probNum SIZE=11> 217 ENDOFHTML 218 219 my ($problem,$problemAttempted, $problemStatus,$longProblemStatus); 220 foreach $problem(@problems) { 221 $problemStatus = getProblemStatus($problem,$psvn); 222 $problemAttempted = getProblemAttempted($problem,$psvn); 223 224 if (!$problemAttempted) { 225 $longProblemStatus = ''; # default value 226 } elsif ($problemStatus >= 0 and $problemStatus <=1 ) { 227 my $percentCorr = int(100*$problemStatus+.5); 228 $longProblemStatus = "${percentCorr}\% correct" 229 } else { 230 $longProblemStatus = 'unknown status'; # default value 231 } 232 print "<OPTION VALUE=$problem>Problem $problem -- $longProblemStatus </OPTION>\n"; 233 } 234 235 ## nice note to warn if there's less than one day left to complete problem set 236 if ($remainingTime<86400 && $remainingTime>0) { 237 $TimeString = "<BR><RM>Note: you have less than one day left 238 to complete this problem set</EM>"; 239 } 240 else { 241 $TimeString = ""; 242 } 243 244 print <<"ENDOFHTML"; 245 </SELECT> 246 <BR> 247 ENDOFHTML 248 249 250 my $practiceUser = $Global::practiceUser; 251 if (($currentTime > $ddts) or ($User =~ /^$practiceUser/)) { 252 print q!<INPUT type="checkbox" name="show_old_answers" value=1> Show my old answers<BR>!; 253 } 254 else { 255 print q!<INPUT type="checkbox" name="show_old_answers" checked value=1> Show my old answers<BR>!; 256 } 257 258 print &sessionKeyInputs(\%inputs); 259 my $mode = $inputs{'Mode'}; 260 $mode = $Global::htmlModeDefault unless ($mode); 261 &displaySelectModeLine($mode); ## displays mode select buttons 262 ## the sub displaySelectModeLine is in 263 ## "${courseScriptsDirectory}$Global::displayMacros_pl" 264 print <<"ENDOFHTML"; 265 <BR> 266 <INPUT TYPE=SUBMIT VALUE="Get Problem"> 267 $TimeString 268 269 </FORM> 270 271 ENDOFHTML 272 273 print "<FORM METHOD=POST ACTION=\"${Global::cgiWebworkURL}welcome.pl\"><P>"; 274 print &sessionKeyInputs(\%inputs); 275 276 print <<"ENDOFHTML"; 277 <INPUT TYPE=HIDDEN NAME="probSetKey" VALUE=$psvn> 278 <INPUT TYPE=SUBMIT VALUE="Problem Sets"> 279 </FORM> 280 281 282 </TD> 283 <!-- Row 1 Column 2 --> 284 <TD> 285 ENDOFHTML 286 287 288 ## process problem and save @printlines 289 my $probHeader = $Global::PROB_HEADER; # default value 290 291 if ( (defined($probHeaderFileName)) and ($probHeaderFileName =~ /\S/)) { 292 $probHeader = $probHeaderFileName; 293 } 294 ## use $probHeader as default unless $probHeaderFileName is defined 295 ## in the set definition file 296 my $source; 297 if (-e "${templateDirectory}$probHeader" ) { 298 unless (-r "${templateDirectory}$probHeader") { 299 wwerror($0, "Can't read ${templateDirectory}$probHeader"); 300 } 301 open(PROB,"<${templateDirectory}$probHeader"); 302 $source = join("",<PROB>); 303 close(PROB); 304 } 305 my %envir=defineProblemEnvir($mode,0,$psvn,$Course); 306 my $pt = new PGtranslator; #pt stands for problem translator; 307 $pt->environment(\%envir); 308 $pt->initialize(); 309 $pt-> set_mask(); 310 $pt->source_string($source); 311 $pt -> unrestricted_load("${courseScriptsDirectory}PG.pl"); 312 $pt -> unrestricted_load("${courseScriptsDirectory}dangerousMacros.pl"); 313 $pt ->translate(); 314 my $PG_PROBLEM_TEXT_REF = $pt->ra_text(); 315 my $PG_HEADER_TEXT_REF = $pt->r_header;#\$PG_HEADER_TEXT; 316 my $PG_ANSWER_HASH_REF = $pt->rh_correct_answers; 317 my $PG_FLAGS_REF =$pt ->rh_flags; 318 319 320 321 my @printlines; 322 if($mode eq "HTML" || $mode eq 'HTML_tth') { 323 @printlines=@{$pt->ra_text()}; 324 } 325 elsif ($mode eq 'Latex2HTML') { 326 @printlines = &createDisplayedInsert($setNumber, 327 $probHeader,$psvn,$Course,$pt->ra_text()); 328 } 329 print @printlines; 330 print <<"ENDOFHTML"; 331 </TD> 332 </TR> 333 </TABLE> 334 ENDOFHTML 335 print &htmlBOTTOM('welcomeAction.pl', \%inputs,'probSetHelp.html'); 336 exit; 337 } ## end of problem selection form and end of sub displayProbSet 338 339 #################### 340 ## subroutines 341 #################### 342 343 $/ = "\n"; 344 sub createTexSource { 345 my $psvn = shift; 346 347 # check that the psvn corresponds to the user and that it is after the open 348 # date. This should only fail if someone is trying to break into WeBWorK. 349 350 &attachProbSetRecord($psvn); 351 $login_name_for_psvn = &getStudentLogin($psvn); 352 attachCLRecord($login_name_for_psvn); 353 354 if ( ( ( $User ne &getStudentLogin($psvn)) ||($currentTime < $odts) ) 355 and ($permissions != $Global::instructor_permissions) 356 and ($permissions != $Global::TA_permissions) 357 ) { 358 &hackerError; 359 exit; 360 } 361 362 my $probSetHeader = $Global::SET_HEADER; 363 364 my $setHeaderFileName = &getSetHeaderFileName($psvn); 365 366 my $answersRequestedQ = 0; 367 $answersRequestedQ= $inputs{'ShowAns'} if defined($inputs{'ShowAns'}); 368 369 my $adts=&getAnswerDate($psvn); 370 my $displayCorrectAnswersQ = 0; #initialize 371 $displayCorrectAnswersQ =1 if $answersRequestedQ && ($currentTime > $adts); 372 $displayCorrectAnswersQ =1 if $answersRequestedQ && ($permissions == $Global::instructor_permissions); 373 374 375 # chdir "$tempDirectory"; 376 # umask(022); 377 378 my $texSource =''; 379 380 # open(OUTPUT, ">${tempDirectory}${texFile}${psvn}.tex") 381 #|| wwerror("Can't create $tempDirectory${texFile}$psvn.tex\n"); 382 383 384 385 print STDERR "%%Creating a tex version of set $setNumber<BR>\n" if $debugON; 386 print STDERR "%%For", &CL_getStudentName($login_name_for_psvn), "psvn=$psvn<BR>\n" if $debugON; 387 388 389 # input TeX preamble 390 # print OUTPUT &texInput($Global::TEX_SET_PREAMBLE); 391 $texSource = &texInput($Global::TEX_SET_PREAMBLE); 392 393 # print TeX Header 394 # print OUTPUT &texInput($Global::TEX_SET_HEADER); 395 $texSource .= &texInput($Global::TEX_SET_HEADER); 396 397 # Print setheader 398 my $mode = "TeX"; 399 my @PG_COMPILE_ERRORS = (); 400 if ( (defined($setHeaderFileName)) and $setHeaderFileName =~ /\S/) { 401 $probSetHeader = $setHeaderFileName; 402 } 403 ## use $probSetHeader as default unless $setHeaderFileName is defined 404 ## in the set definition file 405 if ( open(INPUT,"${templateDirectory}$probSetHeader") ) { 406 407 # ##Determine language 408 409 $probSetHeader =~ /\.([^\.]*)$/; 410 my $displayMode = $1; 411 412 if ($displayMode eq 'pg') { 413 my %envir=defineProblemEnvir($mode,0, $psvn,$Course,undef()); 414 my $input_string= join("",<INPUT> ); 415 my ($PG_PROBLEM_TEXT_REF, $PG_HEADER_TEXT_REF, $PG_ANSWER_HASH_REF, $PG_FLAGS_REF); 416 my $pt = new PGtranslator; #pt stands for problem translator; 417 $pt -> evaluate_modules( @{main::modules_to_evaluate}) ; 418 $pt -> load_extra_packages(@{main::extra_packages_to_be_loaded}); 419 420 # The variables in the two preceding lines are defined in PG_module_list.pl 421 # require "${courseScriptsDirectory}PG_module_list.pl"; 422 # (Modules are defined by require statement above found near the top of this file, outside the loop.) 423 $pt->environment(\%envir); 424 $pt->initialize(); 425 $pt-> set_mask(); 426 $pt->source_string($input_string); 427 $pt -> unrestricted_load("${courseScriptsDirectory}PG.pl"); 428 $pt -> unrestricted_load("${courseScriptsDirectory}dangerousMacros.pl"); 429 $pt ->translate(); 430 $PG_PROBLEM_TEXT_REF = $pt->ra_text(); 431 $PG_HEADER_TEXT_REF = $pt->r_header;#\$PG_HEADER_TEXT; 432 $PG_ANSWER_HASH_REF = $pt->rh_correct_answers; 433 $PG_FLAGS_REF =$pt ->rh_flags; 434 # print OUTPUT @{$PG_PROBLEM_TEXT_REF}; 435 $texSource .= join '', @{$PG_PROBLEM_TEXT_REF}; 436 437 } else { 438 # print OUTPUT "Don't understand languages with extension $displayMode.<BR>\n"; 439 $texSource .= "Don't understand languages with extension $displayMode.<BR>\n"; 440 } 441 close INPUT; 442 } else { 443 print STDERR ( "Can't open ${templateDirectory}${probSetHeader}\n") if $debugON; 444 wwerror("$0", "\n######## Could not open the set header file: ${templateDirectory}${probSetHeader}","",""); 445 } 446 447 448 # Print problems 449 my @problems = sort {$a <=> $b } &getAllProblemsForProbSetRecord($psvn); 450 my @refSubmittedAnswers = (); 451 # print "content-type: text/plain\n\nproblems @problems"; 452 453 my $probNum; 454 foreach $probNum (@problems) { 455 my $source; 456 my $probFileName = &getProblemFileName($probNum,$psvn); 457 if (-e "${templateDirectory}$probFileName" ) { 458 unless (-r "${templateDirectory}$probFileName") { 459 wwerror($0, "Can't read ${templateDirectory}$probFileName"); 460 } 461 open(PROB,"<${templateDirectory}$probFileName"); 462 $source = join("",<PROB>); 463 close(PROB); 464 } 465 local($^W) =0; ##########CHANGE THIS BACK!!!! 466 my %envir=defineProblemEnvir('TeX',$probNum,$psvn,$Course,undef()); 467 my ($PG_PROBLEM_TEXT_REF, $PG_HEADER_TEXT_REF, $PG_ANSWER_HASH_REF, $PG_FLAGS_REF,$PG_EVALUATED_ANSWERS_REF); 468 # 469 my $pt = new PGtranslator; #pt stands for problem translator; 470 $pt->environment(\%envir) ; 471 $pt->initialize(); 472 $pt-> set_mask(); 473 $pt->source_string($source); 474 $pt -> unrestricted_load("${courseScriptsDirectory}PG.pl"); 475 $pt -> unrestricted_load("${courseScriptsDirectory}dangerousMacros.pl"); 476 $pt ->translate(); 477 478 $PG_PROBLEM_TEXT_REF = $pt->ra_text(); 479 $PG_HEADER_TEXT_REF = $pt->r_header;#\$PG_HEADER_TEXT; 480 481 # $PG_ANSWER_HASH_REF = $pt->rh_correct_answers; 482 $PG_EVALUATED_ANSWERS_REF = $pt->process_answers; 483 $PG_FLAGS_REF = $pt ->rh_flags; 484 485 486 # print OUTPUT @{$PG_PROBLEM_TEXT_REF}; 487 $texSource .= join '', @{$PG_PROBLEM_TEXT_REF}; 488 489 if (defined($PG_FLAGS_REF->{'error_flag'}) and $PG_FLAGS_REF->{'error_flag'} ==1) { 490 push(@PG_COMPILE_ERRORS, qq{<A HREF="#problem$probNum">$probNum</A>} ); 491 } 492 if ($displayCorrectAnswersQ) { 493 my %correctAnswerHash = (); 494 495 496 my @correctAnswerList = (); 497 498 my %submittedAnswerHash = (); 499 if ( ref($PG_EVALUATED_ANSWERS_REF) eq 'HASH' ) { 500 %correctAnswerHash = %$PG_EVALUATED_ANSWERS_REF; 501 } else { 502 warn "ERROR: Please pass the PG answer list as a hash not a list."; 503 } 504 505 # insert answers (if any) 506 507 if ( %correctAnswerHash ) { 508 $texSource .= "Correct Answers:\\par\\begin{itemize}\n"; 509 my ($correctFlag,$normalizedCorrectAnswer, 510 $normalizedSubmittedAnswer, 511 $answerMessage) = (); 512 # determine the correct order for the answers 513 my @answer_entry_order = ( defined($pt->{PG_FLAGS_REF}->{ANSWER_ENTRY_ORDER}) ) ? 514 @{$pt->{PG_FLAGS_REF}->{ANSWER_ENTRY_ORDER}} : keys %{$pt->rh_evaluated_answers} ; 515 516 foreach my $ky (@answer_entry_order) { 517 518 $normalizedCorrectAnswer = $correctAnswerHash{$ky}->{correct_ans}; 519 $normalizedCorrectAnswer =~ s/\^/\\\^\{\}/g; 520 $normalizedCorrectAnswer =~ s/\_/\\\_/g; 521 $texSource .= "\\item $normalizedCorrectAnswer\n"; 522 523 } 524 525 $texSource .= "\\end{itemize} \\par\n"; 526 } 527 if (defined($Global::WARNINGS) and $Global::WARNINGS) { 528 my $warnings = '{\\bf WARNINGS:\par{\\tiny ' . $Global::WARNINGS . ' }}'; 529 $warnings =~ s|/|\\\-/|g; #allow linebreaks in the middle of URLs 530 $warnings =~ s/<br>/\\par\n/ig; #introduce breaks at linebreaks and paragraphs 531 $warnings =~ s/<p>/\\par\n/ig; 532 $warnings =~ s/\#/\\\#/g; #protect against some of the symbols which are reserved in tex 533 $warnings =~ s/\_/\\\_/g; 534 $warnings =~ s/\>/\\\>/g; 535 $warnings =~ s/\</\\\</g; 536 $texSource .= $warnings; 537 } 538 $Global::WARNINGS = ''; #reset the Global::WARNINGS parameter 539 } 540 541 542 } 543 544 # print Tex postamble 545 # print OUTPUT &texInput($Global::TEX_SET_FOOTER); 546 $texSource .= &texInput($Global::TEX_SET_FOOTER); 547 548 return \$texSource, \@PG_COMPILE_ERRORS; 549 } 550 551 ################### END main routine ################################## 552 553 sub downloadAllSets { 554 system("/usr/bin/renice +$main::CLASS_DOWNLOAD_NICE -p $$ 1>/dev/null") && warn "Could not renice process. pid $$"; 555 alarm( $main::CLASS_DOWNLOAD_TIME_OUT_CONSTANT); 556 557 my $downloadMulti = "unknown"; 558 $downloadMulti = "multistudent" if $action eq "Get_all_copies"; 559 $downloadMulti = "multiset" if $action eq "Get_hard_copy"; 560 561 my @psvns_to_download = $query->param('local_psvns'); 562 my $num_psvns_to_download = @psvns_to_download; 563 my $max_psvns_to_download = $Global::max_num_of_ps_downloads_allowed; 564 565 if($num_psvns_to_download > 1 and $permissions != $Global::instructor_permissions) { 566 wwerror("Non-professors are not permitted to download more than one problem set at a time."); 567 } 568 569 if(@psvns_to_download > $Global::max_num_of_ps_downloads_allowed) { 570 my $tooManyWhat = $downloadMulti eq "multiset" ? "problem sets" : "students"; 571 wwerror("Too many $tooManyWhat are selected for download.", 572 "The maximum number of $tooManyWhat which can be downloaded at one time is $Global::max_num_of_ps_downloads_allowed." 573 ." You selected $num_psvns_to_download. Go back and select fewer $tooManyWhat." 574 ." (This maximun is set by the variable \$max_num_of_ps_downloads_allowed in Global.pm.)"); 575 } 576 577 my ($cumulativeTexSource, $currentTexSourceRef, $currentTexSource, $currentTexErrorRef); 578 579 # this could be used when eliminating pre-foreach createTexSourceHandleErrors call 580 # s/\\end\{document\}.*?\\begin\{document\}/\n\\newpage\n/s; 581 582 $tempTexFileBaseName = "${tempDirectory}Temp_downloadAllSets_$User"; 583 my $first_psvn = $psvns_to_download[0]; 584 585 my $current_psvn = shift @psvns_to_download; 586 ($currentTexSourceRef, $currentTexErrorRef) = createTexSource($current_psvn); 587 @psvns_to_download = () if(@$currentTexErrorRef); 588 $currentTexSource = $$currentTexSourceRef; 589 $currentTexSource =~ s|\\end\{document\}\s$|\n|s; 590 $cumulativeTexSource .= $currentTexSource; 591 592 foreach $current_psvn (@psvns_to_download) { 593 ($currentTexSourceRef, $currentTexErrorRef) = createTexSource($current_psvn); 594 @psvns_to_download = () if(@$currentTexErrorRef); 595 $currentTexSource = $$currentTexSourceRef; 596 $currentTexSource =~ s|^.*?\\begin\{document\}|\n\\newpage\n|s; 597 $currentTexSource =~ s|\\end\{document\}\s$|\n|s; 598 $cumulativeTexSource .= $currentTexSource; 599 } 600 601 $cumulativeTexSource .= "\n\\end{document}\n"; 602 603 open TEXOUTPUT, ">$tempTexFileBaseName.tex" 604 or wwerror("Can't open $tempTexFileBaseName.tex for output."); 605 print TEXOUTPUT $cumulativeTexSource; 606 close TEXOUTPUT; 607 608 if(@$currentTexErrorRef) { 609 PG_error_print($tempTexFileBaseName, $current_psvn, @$currentTexErrorRef); 610 } else { 611 $downloadType = lc $downloadType; 612 my $mimeType = prepareHardcopy($tempTexFileBaseName, $downloadType); 613 614 my ($setName, $userName); 615 &attachProbSetRecord($first_psvn); 616 if($downloadMulti eq "multistudent") { 617 if($num_psvns_to_download == 1) { 618 $setName = getSetNumber($first_psvn); 619 $userName = getStudentLogin($first_psvn); 620 } else { 621 $setName = getSetNumber($first_psvn); 622 $userName = "multistudent"; 623 } 624 } elsif($downloadMulti eq "multiset") { 625 if($num_psvns_to_download == 1) { 626 $setName = getSetNumber($first_psvn); 627 $userName = getStudentLogin($first_psvn); 628 } else { 629 $setName = "multiset"; 630 $userName = getStudentLogin($first_psvn); 631 } 632 } 633 my $hardCopyName = "$Course.$userName.$setName.$downloadType"; 634 635 open(TEXINPUT, "$tempTexFileBaseName.$downloadType") 636 or wwerror($0, "Can't open $tempTexFileBaseName.$downloadType: $!\n"); 637 print "Content-type: $mimeType\n"; 638 print "Content-disposition: attachment; filename=\"$hardCopyName\"\n\n"; 639 print while (<TEXINPUT>); 640 close TEXINPUT; 641 } 642 } 643 644 sub prepareHardcopy 645 { 646 my ($texFileBaseName, $targetFormat) = @_; 647 my $mimeType; 648 649 chdir $tempDirectory; 650 651 my $dviCommandLine = "$Global::externalLatexPath $texFileBaseName.tex >/dev/null 2>/dev/null"; 652 my $psCommandLine = "$Global::externalDvipsPath -o $texFileBaseName.ps $texFileBaseName.dvi >/dev/null 2>/dev/null"; 653 my $pdfCommandLine = "$Global::externalPs2pdfPath $texFileBaseName.ps $texFileBaseName.pdf"; 654 655 # make sure that you are not using old copies of the following files: 656 unlink("$texFileBaseName.dvi","$texFileBaseName.ps", "$texFileBaseName.pdf"); 657 658 if($targetFormat eq "pdf") { 659 #system($dviCommandLine); -e "$texFileBaseName.dvi" or die "dvi generation failed."; 660 system($dviCommandLine); -e "$texFileBaseName.dvi" or &logPrint($texFileBaseName); 661 # this gives more information about pure TeX errors 662 # (i.e. the .pg file has compiled but the resulting TeX is not well formed.) 663 664 # The following commands don't usually give very useful error messages anyway so just report failure. 665 system($psCommandLine); -e "$texFileBaseName.ps" or die "ps generation failed."; 666 system($pdfCommandLine); -e "$texFileBaseName.pdf" or die "pdf generation failed."; 667 $mimeType = "application/pdf"; 668 } elsif($targetFormat eq "ps") { 669 #system($dviCommandLine); -e "$texFileBaseName.dvi" or die "dvi generation failed."; 670 system($dviCommandLine); -e "$texFileBaseName.dvi" or &logPrint($texFileBaseName); 671 # this gives more information about pure TeX errors 672 # (i.e. the .pg file has compiled but the resulting TeX is not well formed.) 673 system($psCommandLine); -e "$texFileBaseName.ps" or die "ps generation failed."; 674 $mimeType = "application/postscript"; 675 } elsif($targetFormat eq "dvi") { 676 #system($dviCommandLine); -e "$texFileBaseName.dvi" or die "dvi generation failed."; 677 system($dviCommandLine); -e "$texFileBaseName.dvi" or &logPrint($texFileBaseName); 678 # this gives more information about pure TeX errors 679 # (i.e. the .pg file has compiled but the resulting TeX is not well formed.) 680 $mimeType = "application/x-dvi"; 681 } elsif($targetFormat eq "tex") { 682 $mimeType = "application/tex"; 683 } else { 684 die "unrecognized format: $targetFormat"; 685 } 686 687 return $mimeType; 688 } 689 690 sub PG_error_print 691 { 692 my ($tempTexFileBaseName, $current_psvn, @errors) = @_; 693 694 # get set name and student name from psvn 695 &attachProbSetRecord($current_psvn); 696 my $userName = &getStudentLogin($current_psvn); 697 my $setName = &getSetNumber($current_psvn); 698 699 # print error page header 700 print &htmlTOP("PG compile error"); 701 print "<H3>PG error while compiling problem number", (@errors>1) ? 's ' : ' ', 702 join(', ', @errors), " in problem set $setName for $userName.</H3>"; 703 print "<h3>TeX source file:</h3>"; 704 705 # open temp tex file 706 if(open TEXINPUT, "$tempTexFileBaseName.tex") { 707 print "<pre>\n"; 708 my $lineNumber = 1; 709 while(<TEXINPUT>) { 710 if(/<A NAME/) { print $_; } 711 else { print protect_HTML("$lineNumber $_"), "\n"; } 712 $lineNumber++; 713 } 714 print "</pre>\n"; 715 close TEXINPUT; 716 } else { 717 print "<p>Unable to open TeX source file:<br><tt>$tempTexFileBaseName.tex</tt></p>"; 718 } 719 720 # print page footer 721 print &htmlBOTTOM("welcomeAction.pl", \%inputs); 722 exit; 723 } 724 725 # ----- 726 727 sub logPrint { 728 my $texFileBaseName=shift; 729 print &htmlTOP("TeX Error or error in creating PostScript file"); 730 open (LOGFILE, " $texFileBaseName.log") 731 || print "<H3>Can't open log file:</H3> path= $texFileBaseName.log<BR>$!<BR><BR>" ; 732 733 734 print "<H3>TeX Error Log:</H3>"; 735 my $print_error_switch = ($debugON) ? 1: 0; 736 my $out=''; 737 #warn ord $/, ord "\n", ord "\r"; 738 #warn "length of separator = ", length($/); 739 $/ = "\n"; 740 #warn ord $/, ord "\n", ord "\r"; 741 while (<LOGFILE>) { 742 $out = $_; 743 $print_error_switch = 1 if $out =~ /^!/; # after a fatal error start printing messages 744 print protect_HTML($out)."<BR>\n" if $print_error_switch; 745 } 746 close(LOGFILE); 747 748 open (TEXFILE, "$texFileBaseName.tex") 749 || print "<H3>Can't open tex source file:</H3> path= $texFileBaseName.tex:<BR> $!<BR><BR>\n"; 750 print "<BR>\n<H3>TeX Source File:</H3><BR>\n"; 751 print "<PRE>"; 752 753 my $lineNumber = 1; 754 while (<TEXFILE>) { 755 print protect_HTML("$lineNumber $_")."\n"; 756 $lineNumber++; 757 } 758 close(TEXFILE); 759 print "</PRE>"; 760 print &htmlBOTTOM("welcomeAction.pl", \%inputs); 761 } 762 sub protect_HTML { 763 my $line = shift; 764 chomp($line); 765 $line =~s/\&/&/g; 766 $line =~s/</</g; 767 $line =~s/>/>/g; 768 $line; 769 } 770 sub selectionError { 771 print &htmlTOP("Selection error"); 772 print"<H2>Error:</H2> You must first select a problem set in order to download a hard copy!\n"; 773 print "<FORM METHOD=POST ACTION=\"${Global::cgiWebworkURL}welcome.pl\"><P>"; 774 print &sessionKeyInputs(\%inputs); 775 print <<"ENDOFHTML"; 776 <INPUT TYPE=SUBMIT VALUE="Return to Welcome Page"> 777 </FORM> 778 ENDOFHTML 779 print &htmlBOTTOM("welcomeAction.pl", \%inputs); 780 } 781 782 sub probSet_htmlTOP { 783 my ($title, $bg_url) = @_; 784 my $background_url = $bg_url || $Global::background_plain_url; 785 786 787 my $out = <<ENDhtmlTOP; 788 content-type: text/html 789 Expires: 0 790 791 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> 792 <HTML> 793 <HEAD> 794 <TITLE>$title</TITLE> 795 </HEAD> 796 <BODY BACKGROUND="$background_url"><p> 797 <P> 798 799 ENDhtmlTOP 800 $out; 801 } 802 803 sub probSet_titleBar { 804 my ($title) = @_; 805 my $title_bar = ""; 806 $title_bar .= qq{ 807 <TABLE BORDER="0" WIDTH="100%"> 808 <TR ALIGN=CENTER > 809 <TD ALIGN=LEFT > 810 <A HREF="$Global::webworkDocsURL"> 811 <IMG SRC="$Global::squareWebworkGif" BORDER=1 ALT="WeBWorK"></A> 812 </TD> 813 <TD VALIGN=MIDDLE> 814 <H2 ALIGN=CENTER> 815 $title 816 </H2> 817 </TD> 818 <TD ALIGN=RIGHT > 819 <FORM METHOD=POST ACTION=\"${Global::cgiWebworkURL}welcome.pl\"><P> 820 }; 821 my $inputkeys = &sessionKeyInputs(\%inputs); 822 823 $title_bar .= qq{ 824 $inputkeys 825 <INPUT TYPE=HIDDEN NAME=\"probSetKey\" VALUE=$psvn> 826 <INPUT TYPE=SUBMIT VALUE=\"Problem Sets\"> 827 </FORM> 828 </TD> 829 </TABLE> 830 }; 831 $title_bar; 832 } 833 834 sub hackerError { ## prints hacker error message 835 836 my $msg = "Attempt to hack into WeBWorK \n Remote Host is: ". remote_host()."\n"; 837 $msg .= query_string; 838 &Global::log_error('hacker error', $msg); ## log attempt 839 840 ## notify by email 841 842 my $toAdd = $Global::feedbackAddress; 843 844 my $emailMsg = "To: $toAdd 845 Subject: Attempt to hack into WeBWorK 846 847 Here are the details on the attempt to hack into weBWorK:\n 848 $msg 849 \n"; 850 851 my $smtp = Net::SMTP->new($Global::smtpServer, Timeout=>20); 852 $smtp->mail($Global::webmaster); 853 $smtp->recipient($Global::feedbackAddress); 854 $smtp->data($msg); 855 $smtp->quit; 856 857 858 # my $SENDMAIL = $Global::SENDMAIL; 859 # open (MAIL,"|$SENDMAIL"); 860 # print MAIL "$emailMsg"; 861 # close (MAIL); 862 863 print &htmlTOP("Hacker Error"), 864 "<H2>Error:Please do not try to hack into WeBWorK!</H2>", 865 startform(-action=>"${Global::cgiWebworkURL}${Global::welcomeAction_CGI}"), 866 "<p>", 867 &sessionKeyInputs(\%inputs), 868 hidden(-name=>'local_psvns', -value=>$psvn), 869 hidden(-name=>'action', -value=>'Do_problem_set'), 870 submit(-value=>"Return to Problem Set"), 871 endform(), 872 &htmlBOTTOM($0, \%inputs); 873 } 874 875 sub defineProblemEnvir { 876 my ($mode,$probNum,$psvn,$courseName,$refSubmittedAnswers) = @_; 877 my %envir=(); 878 my $loginName = &getStudentLogin($psvn); 879 ##how to put an array submittedAnswers in a hash?? 880 $envir{'refSubmittedAnswers'} = $refSubmittedAnswers if defined($refSubmittedAnswers); 881 $envir{'psvnNumber'} = $psvn; 882 $envir{'psvn'} = $psvn; 883 $envir{'studentName'} = &CL_getStudentName($loginName); 884 $envir{'studentLogin'} = $loginName; 885 $envir{'sectionName'} = &CL_getClassSection($loginName); 886 $envir{'sectionNumber'} = &CL_getClassSection($loginName); 887 $envir{'recitationName'} = &CL_getClassRecitation($loginName); 888 $envir{'recitationNumber'} = &CL_getClassRecitation($loginName); 889 $envir{'setNumber'} = &getSetNumber($psvn); 890 $envir{'questionNumber'} = $probNum; 891 $envir{'probNum'} = $probNum; 892 $envir{'openDate'} = &getOpenDate($psvn); 893 $envir{'formatedOpenDate'} = &formatDateAndTime(&getOpenDate($psvn)); 894 $envir{'formattedOpenDate'} = &formatDateAndTime(&getOpenDate($psvn)); 895 $envir{'dueDate'} = &getDueDate($psvn); 896 $envir{'formatedDueDate'} = &formatDateAndTime(&getDueDate($psvn)); 897 $envir{'formattedDueDate'} = &formatDateAndTime(&getDueDate($psvn)); 898 $envir{'answerDate'} = &getAnswerDate($psvn); 899 $envir{'formatedAnswerDate'} = &formatDateAndTime(&getAnswerDate($psvn)); 900 $envir{'formattedAnswerDate'} = &formatDateAndTime(&getAnswerDate($psvn)); 901 $envir{'problemValue'} = &getProblemValue($probNum,$psvn); 902 $envir{'fileName'} = &getProblemFileName($probNum,$psvn); 903 $envir{'probFileName'} = &getProblemFileName($probNum,$psvn); 904 $envir{'languageMode'} = $mode; 905 $envir{'displayMode'} = $mode; 906 $envir{'outputMode'} = $mode; 907 $envir{'courseName'} = $courseName; 908 $envir{'sessionKey'} = ( defined($inputs{'key'}) ) ?$inputs{'key'} : " "; 909 910 # initialize constants for PGanswermacros.pl 911 $envir{'numRelPercentTolDefault'} = getNumRelPercentTolDefault(); 912 $envir{'numZeroLevelDefault'} = getNumZeroLevelDefault(); 913 $envir{'numZeroLevelTolDefault'} = getNumZeroLevelTolDefault(); 914 $envir{'numAbsTolDefault'} = getNumAbsTolDefault(); 915 $envir{'numFormatDefault'} = getNumFormatDefault(); 916 $envir{'functRelPercentTolDefault'} = getFunctRelPercentTolDefault(); 917 $envir{'functZeroLevelDefault'} = getFunctZeroLevelDefault(); 918 $envir{'functZeroLevelTolDefault'} = getFunctZeroLevelTolDefault(); 919 $envir{'functAbsTolDefault'} = getFunctAbsTolDefault(); 920 $envir{'functNumOfPoints'} = getFunctNumOfPoints(); 921 $envir{'functVarDefault'} = getFunctVarDefault(); 922 $envir{'functLLimitDefault'} = getFunctLLimitDefault(); 923 $envir{'functULimitDefault'} = getFunctULimitDefault(); 924 $envir{'functMaxConstantOfIntegration'} = getFunctMaxConstantOfIntegration(); 925 $envir{'numOfAttempts'} = undef(); # this is defined only for problems 926 927 # defining directorys and URLs 928 $envir{'templateDirectory'} = &getCourseTemplateDirectory(); 929 $envir{'classDirectory'} = $Global::classDirectory; 930 $envir{'cgiDirectory'} = $Global::cgiDirectory; 931 $envir{'macroDirectory'} = getCourseMacroDirectory(); 932 $envir{'courseScriptsDirectory'} = getCourseScriptsDirectory(); 933 $envir{'htmlDirectory'} = getCourseHtmlDirectory(); 934 $envir{'htmlURL'} = getCourseHtmlURL(); 935 $envir{'tempDirectory'} = getCourseTempDirectory(); 936 $envir{'tempURL'} = getCourseTempURL(); 937 $envir{'scriptDirectory'} = $Global::scriptDirectory; 938 $envir{'webworkDocsURL'} = $Global::webworkDocsURL; 939 $envir{'externalTTHPath'} = $Global::externalTTHPath; 940 941 942 $envir{'inputs_ref'} = \%inputs; 943 944 945 my $seed = &getProblemSeed($probNum, $psvn); 946 $seed = 1111 unless defined($seed); 947 $envir{'problemSeed'} = $seed if defined($seed); 948 949 # here is a way to pass environment variables defined in webworkCourse.ph 950 my $k; 951 foreach $k (keys %Global::PG_environment ) { 952 $envir{$k} = $Global::PG_environment{$k}; 953 } 954 %envir; 955 } 956 957 BEGIN { 958 959 960 # This subroutine cleans up temporary files after the postscript copy has been created. 961 # 962 sub cleanup_downloadPS { 963 964 unless (defined($action ) and ($action eq 'Do problem set' or $action eq 'Do_problem_set')) { 965 my $ERRORS = $save_errors; 966 unless ($debugON) { #clean up the directory 967 eval { 968 chdir $tempDirectory; 969 unlink( 970 "#tempTexFileBaseName.dvi", 971 "$tempTexFileBaseName.ps", 972 "$tempTexFileBaseName.pdf", 973 "$tempTexFileBaseName.log", 974 "$tempTexFileBaseName.aux", 975 "$tempTexFileBaseName.tex" 976 ); 977 unlink("${tempDirectory}eps/${login_name_for_psvn}*.eps"); 978 }; # clean up 979 $ERRORS .= $ERRORS . $@; 980 } 981 my $query = query_string(); 982 $query = "" unless defined($query); 983 wwerror("$0", "ERROR: in downloadPS subroutine of welcomeAction.pl $ERRORS","","",$query) if $ERRORS; 984 } 985 } 986 } 987 988 END { 989 if (defined($main::SIG_TIME_OUT) && $main::SIG_TIME_OUT == 1) { 990 alarm(0); # turn off the alarm 991 my $hard_copy_message = qq{Content-type: text/html\n\n 992 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> 993 <HTML><BODY BGCOLOR = "FF99CC"> 994 <BLOCKQUOTE><H3>WeBWorK hard copy download time out.</H3>\n 995 <H4>This download was cancelled because it took more than $main::TIME_OUT_CONSTANT seconds.</H4> This may be because the 996 WeBWorK server is extraordinarily busy, or because there was an error in the problem, 997 or because you tried to download a set with too many problems (more than 50).<P>\n 998 Use the back button to return to the previous page and try again.<BR>\n 999 If the problem is repeated you can report this to your instructor using the feedback button. 1000 <P> 1001 Because the WeBWorK server at the Unversity of Rochester is experiencing heavy use we have made downloading 1002 hard copies a low priority during the times of very heavy useage. It will be helpful if you 1003 download hard copies during times when the load is not too heavy. 1004 <P> 1005 The load is usually heaviest in the evenings , particularly a few hours before assignments 1006 are due. The best times to download hard copies are in the morning and afternoon 1007 -- or an hour after the due date and time of the previous assignment -- nobody is using the system then :-) 1008 </BLOCKQUOTE></BODY></HTML> 1009 }; 1010 my $do_problem_message = qq{Content-type: text/html\n\n 1011 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> 1012 <HTML><BODY BGCOLOR = "FF99CC"> 1013 <BLOCKQUOTE><H3>WeBWorK heavy useage time out.</H3>\n 1014 <H4>Your request (action = $action) was cancelled because it took more than $main::TIME_OUT_CONSTANT seconds.</H4> 1015 This is probably because the 1016 WeBWorK server is extraordinarily busy.<P>\n 1017 You should be warned that WeBWorK response will be unusually slow. If possible you should try 1018 to use WeBWorK at another time when the load is not as high. The highest useage periods are in the 1019 evening, particularly in the two hours before assignments are due.<P>\n 1020 Use the back button to return to the previous page and try again.<P>\n 1021 If the high useage problem continues you can report this to your instructor using the feedback button. 1022 <P> 1023 1024 </BLOCKQUOTE></BODY></HTML> 1025 }; 1026 if ($action eq 'Get hard copy' or $action eq 'Get_hard_copy') { 1027 print $hard_copy_message; 1028 } else{ 1029 print $do_problem_message; 1030 } 1031 1032 1033 } 1034 1035 # begin Timing code 1036 if( $main::logTimingData == 1 ) { 1037 my $endTime = new Benchmark; 1038 my $error_str=''; 1039 1040 if ($main::SIGPIPE) { 1041 $error_str = 'broken PIPE--'; 1042 } 1043 elsif ($main::SIG_TIME_OUT) { 1044 $error_str = "TIME_OUT after $main::TIME_OUT_CONSTANT secs --"; 1045 } 1046 elsif ($action eq 'Get hard copy' or $action eq 'Get_hard_copy') { 1047 $error_str = 'successful download -- '; 1048 } 1049 1050 &Global::logTimingInfo($main::beginTime,$endTime,$error_str.'welcomeAction.pl',$Course,$User); 1051 } 1052 # end Timing code 1053 cleanup_downloadPS(); 1054 } 1055 1056 1;
| aubreyja at gmail dot com | ViewVC Help |
| Powered by ViewVC 1.0.9 |