#!/usr/ucb/perl # # CAPA Discussion Forum # version 1.2c # # Michigan State University # Department of Physics and Astronomy # # Ryan J. Shaltry # tech4@msue.msu.edu require "capadiscuss.setup"; require "capadiscuss_html"; ################################################ ## Configuration - Change these appropriately ## ################################################ # capadiscuss.setup ################################################ ## End Configuration ########################### ################################################ print "Content-type: text/html\n\n"; &form_info; $yp = "19"; # define variables $class = $form{'CLASS'}; $snum = $form{'SNUM'}; $capaid = $form{'CAPAID'}; $setid = $form{'SETID'}; $action = $form{'ACTION'}; $file = $form{'FILE'}; $probnum = $form{'PROBNUM'}; $replynum = $form{'REPLYNUM'}; $psetid = $form{'PSETID'}; if($psetid eq "") { $psetid = $setid; } &GetTeacherInfo; # check for valid studentnumber/capaid &ValidateUser; # grab username from student number &UserInfo($snum); &GetDateTime; # call appropriate sr if($action eq "newset" ) { &NewSet; } if($action eq "viewset" || $action eq "" ) { &ViewSet; } if($action eq "viewproblem" ) { &ViewProblem; } if($action eq "post" ) { &Post; } if($action eq "postsubmit" ) { &PostSubmit; } if($action eq "delmsgpre" ) { &DelMsgPre; } if($action eq "delmsg" ) { &DelMsg; } if($action eq "hidemsgpre" ) { &HideMsgPre; } if($action eq "hidemsg" ) { &HideMsg; } if($action eq "unhidemsgpre" ) { &UnHideMsgPre; } if($action eq "unhidemsg" ) { &UnHideMsg; } if($action eq "admin" ) { &AdminMain; } if($action eq "adminusersearch" ) { &AdminUserSearch; } if($action eq "adminusersearchsubmit" ) { &AdminUserSearchSubmit; } if($action eq "viewinfofile" ) { &ViewInfoFile; } if($action eq "topmsg" ) { &TopMsg("top"); } if($action eq "untopmsg" ) { &TopMsg(""); } exit; ####################### ## Begin Subroutines ## ####################### sub NewSet { &Log("NewSet"); if($setid <= $psetid) { #grab capaid @allcapaid = `allcapaid -s $setid -e $setid -stu $snum -c $capadir/$class -i`; $capaid = $allcapaid[2]; chop $capaid; chop $capaid; &ViewSet; } opendir(DDIR,"$capadir/$class/discussion"); @sets = grep(/[0-9]/,sort(readdir(DDIR))); closedir(DDIR); $pdset = "\n"; &NewSetHTML; exit; } sub ViewSet { &Log("ViewSet"); &CheckAdmin; $adminbutton = ""; if($validadmin eq "yes") { $adminbutton = &AdminButtonHTML; } $capasbin = "$capasbin/$teachdir/capasbin"; &SetJumpBox; opendir(FORUM,"$capadir/$class/discussion/$setid"); @dir = sort(readdir(FORUM)); closedir(FORUM); @infofiles = grep(/.info/,@dir); $infostring = ""; $backfunction = "viewset"; foreach $infofile(@infofiles) { $infodesc = $infofile; $infodesc =~ s/.info//g; $infodesc =~ s/_/ /g; $infostring .= &InfoButtonHTML; } foreach $i(@dir) { $probnum = &RemZero(substr($i,0,6)); if($found[$probnum] eq "") { $found[$probnum] = "0"; } $found[$probnum] = $found[$probnum] + 1; } $maxprobs = &MaxProbs($setid); # split table (if more than 15 problems) $bigtable = "no"; if($maxprobs > 5) { $bigtable = "yes"; $col1size = int ($maxprobs / 2); $col2size = $maxprobs - $col1size; if($col1size < $col2size) { $t = $col1size; $col1size = $col2size; $col2size = $t; } } &ViewSetTitleHTML; if($bigtable eq "no") { &ViewSetTopSmallHTML; } else { &ViewSetTopBigHTML; } $col = 1; for($probnum=1; $probnum<=$maxprobs; $probnum++) { if($col eq "1" && $probnum > $col1size && $bigtable eq "yes") { $col = 2; &ViewSetEndColHTML; &ViewSetTopSmallHTML; } if($found[$probnum] ne "") { opendir(MSG,"$capadir/$class/discussion/$setid"); @msgs = grep(/.msg/,sort(readdir(MSG))); closedir(MSG); foreach $msg(@msgs) { if(&RemZero(substr($msg,0,6)) eq $probnum) { push(@good,$msg); } } &OpenMsg("$capadir/$class/discussion/$setid/$good[$#good]"); $lastpost = "$date at $time"; $posts = $found[$probnum]; } else { $lastpost = "--"; $posts = "0"; } &ViewSetGutsHTML; } &ViewSetBotHTML; exit; } sub ViewProblem { &Log("ViewProblem"); # check if user is administrator (for admin button) &CheckAdmin; if($validadmin eq "yes") { $adminbutton = &AdminButtonHTML; } else { $adminbutton = ""; } opendir (MSGS,"$capadir/$class/discussion/$setid"); @msgs = sort(readdir(MSGS)); closedir(MSGS); # search for top message @top = grep (/top/, @msgs); $topmsg = ""; print "$#top"; if($#top ne "0") { $pnum = &AddZero($probnum); foreach $entry(@top) { $find = $entry =~ s/\A$pnum/$pnum/o; if($find eq "1") { $topmsg = $entry; @msgs = grep(!/$topmsg/,@msgs); unshift(@msgs,$topmsg); print "$topmsg"; } } } $msgfind = "no"; $msgcount = 0; $capasbin = "$capasbin/$teachdir/capasbin"; foreach $i(@msgs) { $pn = &RemZero(substr($i,0,6)); if($pn eq $probnum) { $msgcount++; $msgfind = "yes"; &OpenMsg("$capadir/$class/discussion/$setid/$i"); if($status eq "hidden" && $validadmin ne "yes") { $msgcount--; $msgfind = "no"; } if($msgcount eq "1") { $postbutton = &ReplyButtonHTML; &ProblemJumpBox; &ViewProblemTopHTML; } ($token1,$token2) = split(/\|/,$poster); chop $token2; if($token1 eq "Anonymous") { if($validadmin eq "yes") { $poster = "$token2 (anonymously)"; } else { $poster = "$token1"; $email = ""; } } $topfind = grep(/-top.msg/,$i); if($validadmin eq "yes") { $file = "$i"; $delbutton = &DelButtonHTML; $hidebutton = &HideButtonHTML; $topbutton = &TopButtonHTML; if($topfind eq "1") { $topbutton = &UnTopButtonHTML; } } $subjectbgcolor = "#92D1D0"; if($topfind eq "1") { $subjectbgcolor = "blue"; } $messagenote = ""; if($validadmin eq "yes" || $status eq "public") { if($status eq "hidden") { $subjectbgcolor = "red"; $hidebutton = &UnHideButtonHTML; $messagenote = "Hidden by $hiddenuser on $hiddendate at $hiddentime from $hiddenaddr"; } &ViewProblemGutsHTML; } } } &ViewProblemBotHTML; if($msgfind eq "no") { $postbutton = &PostNewButtonHTML; &ProblemJumpBox; &ViewProblemTopHTML; &ViewProblemNoneHTML; &ViewProblemBotHTML; } exit; } sub ViewInfoFile { open(INFOFILE,"$capadir/$class/discussion/$setid/$file"); @file = ; closedir(INFOFILE); print ""; $backfunction = $form{'BACKFUNCTION'}; &InfoBackButtonHTML; foreach $line(@file) { print "$line"; } exit; } sub Post { local(@msgs,$pn,$msg); # grab last message in thread opendir(MSGS,"$capadir/$class/discussion/$setid"); @msgs = grep(/.msg/,sort(readdir(MSGS))); closedir(MSGS); foreach $msg(@msgs) { $pn = &RemZero(substr($msg,0,6)); if($pn eq $probnum) { $lastfile = $msg; } } $PostType = "New Message"; if($lastfile ne "") { &OpenMsg("$capadir/$class/discussion/$setid/$lastfile"); if($status eq "public" || $validadmin eq "yes") { ($poster,$rposter) = split(/\|/,$poster); $inreplyto = &InReplyToHTML; $PostType = "Reply"; } } &PostHTML; exit; } sub PostSubmit { local($message,$subject,$date); $message = $form{'message'}; $subject = $form{'subject'}; if($message eq "" || $subject eq "") { &MFPostReplyHTML; } &Log("Post"); # find last message in thread opendir(FORUM,"$capadir/$class/discussion/$setid"); @dir = sort(readdir(FORUM)); closedir(FORUM); $probnum = &AddZero($probnum); $replynum = "000000"; foreach $msg(@dir) { if(substr($msg,0,6) eq $probnum) { $replynum = &AddZero(&RemZero(substr($msg,7,6)) + 1); } } $date = substr($RunonDate,0,4) . $yp . substr($RunonDate,4,2); &WriteMsg("$capadir/$class/discussion/$setid/$probnum-$replynum-$date-000000.msg"); $probnum = &RemZero($probnum); &PostDoneHTML; exit; } sub DelMsgPre { &CheckAdmin('kill'); &OpenMsg("$capadir/$class/discussion/$setid/$file"); &DelMsgPreHTML; exit; } sub DelMsg { &CheckAdmin('kill'); unlink("$capadir/$class/discussion/$setid/$file"); &DelMsgDoneHTML; exit; } sub HideMsgPre { &CheckAdmin('kill'); &OpenMsg("$capadir/$class/discussion/$setid/$file"); &HideMsgPreHTML; exit; } sub HideMsg { &CheckAdmin('kill'); open(MSG,"$capadir/$class/discussion/$setid/$file"); @msg = ; close(MSG); unlink("$capadir/$class/discussion/$setid/$file"); open(MSG,">$capadir/$class/discussion/$setid/$file"); for($i=0;$i<=5;$i++) { print MSG "$msg[$i]"; } print MSG "hidden|$username|$HyphenDate|$Time|$ENV{'REMOTE_ADDR'}\n"; close(MSG); &HideMsgDoneHTML; } sub UnHideMsgPre { &CheckAdmin('kill'); &OpenMsg("$capadir/$class/discussion/$setid/$file"); &UnHideMsgPreHTML; exit; } sub UnHideMsg { &CheckAdmin('kill'); open(MSG,"$capadir/$class/discussion/$setid/$file"); @msg = ; close(MSG); unlink("$capadir/$class/discussion/$setid/$file"); open(MSG,">$capadir/$class/discussion/$setid/$file"); for($i=0;$i<=5;$i++) { print MSG "$msg[$i]"; } print MSG "public||||}\n"; close(MSG); &UnHideMsgDoneHTML; } sub TopMsg { &CheckAdmin('kill'); $ext = shift(@_); open(MSG,"$capadir/$class/discussion/$setid/$file"); @msg = ; close(MSG); unlink("$capadir/$class/discussion/$setid/$file"); ($filename, $extension) = split(/\./,$file); $filename = "$filename-$ext.msg"; open(MSG,">$capadir/$class/discussion/$setid/$filename"); for($i=0;$i<=6;$i++) { print MSG "$msg[$i]"; } close(MSG); if($ext eq "") { $function = "restored to its original position in the thread."; } else { $function = "moved to the top of the thread list."; } &TopMsgDoneHTML; } ############################### ## Administrator Subroutines ## ############################### sub AdminMain { &CheckAdmin('kill'); &AdminMainHTML; exit; } sub AdminUserSearch { &CheckAdmin('kill'); &AdminUserSearchHTML; exit; } sub AdminUserSearchSubmit { local($sname,$semail,$saction,$sset,$sprob,$sdate,$stime); &CheckAdmin('kill'); $query = $form{'usersearch'}; open(LOG,"$capadir/$class/discussion/logs/access.log"); @log = ; close(LOG); @linematches = grep /$query/, @log; foreach $line(@linematches) { print $line; } exit; } ###################### ## Misc Subroutines ## ###################### sub OpenMsg { local($filename,$statusl); $filename = shift(@_); open (MSG,"$filename"); @msg = ; close(MSG); $poster = $msg[0]; $date = $msg[1]; $time = $msg[2]; $subject = $msg[3]; $email = $msg[4]; $message = $msg[5]; $statusl = $msg[6]; ($status, $hiddenuser, $hiddendate, $hiddentime, $hiddenaddr) = split(/\|/,$statusl); } sub WriteMsg { local($filename,$message); $filename = shift(@_); # add sr to grab e-mail address of user $message = $form{'message'}; $message =~ s/\n\r\n/

/g; $message =~ s/\n/
/g; # check if posted anonymously if($form{'ANONYMOUS'} eq "yes") { $username = "Anonymous|$username"; } open (MSG,">$filename"); print MSG "$username\n"; print MSG "$HyphenDate\n"; print MSG "$Time\n"; print MSG "$subject\n"; print MSG "$email\n"; print MSG "$message\n"; print MSG "public||||\n"; close(MSG); } sub GetTeacherInfo { local($capa5dir,$classname,$tdir,@classconf); # open/read class.conf file open (CLASSCONF,"$capabin/class.conf"); @classconf = ; close(CLASSCONF); $found eq "no"; foreach $line(@classconf) { ($classname,$capa5dir,$tdir) = split(/[\t\ ]+/,$line); if($classname eq $class) { $teachdir = $tdir; $capadir = $capa5dir; $found = "yes"; } } if($found eq "no") { &InvalidVarsHTML; } chop $teachdir; } sub CheckAdmin { local($asection,@adminsections,$line,@capaconfig,$command,$value, $adminsection,@classl,$course,$coursenum,$section,$stunum,$a); $validadmin = "no"; $mode = shift(@_); # open 'capa.config' file (for admin section read) open(CAPACONFIG,"$capadir/$class/capa.config"); @capaconfig = ; close(CAPACONFIG); foreach $line(@capaconfig) { chop $line; ($command,$value) = split(/\ =\ /,$line); if($command eq "admin_section") { $adminsection = $value; } } @adminsections = split(/\,/,$adminsection); # open 'classl' file open(CLASSL,"$capadir/$class/classl"); @classl = ; close(CLASSL); foreach $line(@classl) { chop $line; ($course,$coursenum,$section,$stunum,$a) = split(/\ +/,$line); $snum =~ tr/a-z/A-Z/; $stunum =~ tr/a-z/A-Z/; $section = &RemZero($section); foreach $asection(@adminsections) { if(&RemZero($section) eq &RemZero($asection) && $stunum eq $snum) { $validadmin = "yes"; } } } if($validadmin eq "no" && $mode eq "kill") { &NotAdminHTML; } } sub ValidateUser { local(@allcapaid,@classl,$line); open (CLASSL,"$capadir/$class/classl"); @classl = ; close(CLASSL); $valid = "no"; foreach $line(@classl) { if(substr($line,15,8) eq substr($snum,1,8)) { $valid = yes; } } if($valid eq "no") { &InvalidVarsHTML; } # check w/ allcapaid program @allcapaid = `allcapaid -s $setid -e $setid -stu $snum -c $capadir/$class -i`; chop $allcapaid[2]; chop $allcapaid[2]; if($allcapaid[2] ne $capaid) { if($action ne "newset") { &BadPassHTML; } &NewSet; } } sub UserInfo { local($line,@classl,$last,$first,$middle); open (CLASSL,"$capadir/$class/classl"); @classl = ; close(CLASSL); foreach $line(@classl) { if(substr($line,15,8) eq substr($snum,1,8)) { $username = substr($line,24,36); $email = substr($line,60,45); } } ($last, $first, $middle) = split(/\ +/,$username); chop $last; $username = "$first $last"; $email =~ s/\ //g; chop $email; } sub MaxProbs { open (SETRECORD,"$capadir/$class/records/set$setid.db"); @setrecord = ; close(SETRECORD); chop $setrecord[0]; return $setrecord[0]; } sub ProblemJumpBox { $pdprob = ""; } sub SetJumpBox { opendir(DDIR,"$capadir/$class/discussion"); @sets = grep(/[0-9]/,sort(readdir(DDIR))); closedir(DDIR); $pdset = ""; } sub AddZero { $string = shift(@_); while(length($string) < 6) { $string = "0$string"; } return $string; } sub RemZero { $string = shift(@_); $fc = substr($string,0,1); while($fc eq "0") { $string =~ s/.//; $fc = substr($string,0,1); } return $string; } sub FormatDate { $string = shift(@_); $month = substr($string,0,2); $day = substr($string,2,2); $year = substr($string,4,4); $string = "$month-$day-$year"; return $string; } #################### ## Get SubRoutine ## #################### sub form_info { read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'}); # Split the name-value pairs @pairs = split(/&/, $buffer); foreach $pair (@pairs) { ($name, $value) = split(/=/, $pair); # Un-Webify plus signs and %-encoding $value =~ tr/+/ /; $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg; $value =~ s///g; if ($allow_html != 1) { $value =~ s/<([^>]|\n)*>//g; } $form{$name} = $value; } } ################## ## Date/Time sr ## ################## sub GetDateTime { ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime (time); $mon++; if ($hour < 12) { $AMPM = "AM"; } if ($hour > 12) { $hour = $hour - 12; $AMPM = "PM"; } if ($hour == 12) { $AMPM = "PM"; } if ($hour == 0) { $hour = "12"; } $min = sprintf ("%2d", $min); $min =~tr/ /0/; $mon = sprintf ("%2d", $mon); $mon =~tr/ /0/; $mday = sprintf ("%2d", $mday); $mday =~tr/ /0/; $HyphenDate = ("$mon" . "-" . "$mday" . "-" . "$year"); $RunonDate = ("$mon$mday$year"); $Time = ("$hour" . ":" . "$min" . " " . "$AMPM"); } ######################## ## Logging Subroutine ## ######################## sub Log { $logmsg = shift(@_); &GetDateTime; &Lock("lock.file"); open(LOG,">>$capadir/$class/discussion/logs/access.log"); print LOG "$snum|$capaid|$username|$email|$logmsg|$setid|$probnum|$HyphenDate|$Time\n"; close(LOG); &Unlock("lock.file"); } ############################ ## Lock/Unlock Subroutine ## ############################ sub Lock { local ($lockname) = @_; local ($endtime); $endtime = 15; $endtime = time + $endtime; while (-e $lockname && time < $endtime) { open (LOCKFILE, ">$lockname"); } sub Unlock { local ($lockname) = @_; close (LOCKFILE); unlink ($lockname); } } ###################### ## HTML Subroutines ## ###################### ## CapaDiscuss HTML Subroutines # capadiscuss_html ## end capadiscuss