Annotation of loncom/interface/loncommon.pm, revision 1.38

1.10      albertel    1: # The LearningOnline Network with CAPA
1.1       albertel    2: # a pile of common routines
1.10      albertel    3: #
1.38    ! albertel    4: # $Id: loncommon.pm,v 1.37 2002/05/09 15:56:02 matthew Exp $
1.10      albertel    5: #
                      6: # Copyright Michigan State University Board of Trustees
                      7: #
                      8: # This file is part of the LearningOnline Network with CAPA (LON-CAPA).
                      9: #
                     10: # LON-CAPA is free software; you can redistribute it and/or modify
                     11: # it under the terms of the GNU General Public License as published by
                     12: # the Free Software Foundation; either version 2 of the License, or
                     13: # (at your option) any later version.
                     14: #
                     15: # LON-CAPA is distributed in the hope that it will be useful,
                     16: # but WITHOUT ANY WARRANTY; without even the implied warranty of
                     17: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                     18: # GNU General Public License for more details.
                     19: #
                     20: # You should have received a copy of the GNU General Public License
                     21: # along with LON-CAPA; if not, write to the Free Software
                     22: # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
                     23: #
                     24: # /home/httpd/html/adm/gpl.txt
                     25: #
                     26: # http://www.lon-capa.org/
                     27: #
1.12      harris41   28: # YEAR=2001
                     29: # 2/13-12/7 Guy Albertelli
1.17      harris41   30: # 12/11,12/12,12/17 Scott Harrison
1.18      www        31: # 12/21 Gerd Kortemeyer
1.20      www        32: # 12/21 Scott Harrison
1.22      www        33: # 12/25,12/28 Gerd Kortemeyer
1.23      www        34: # YEAR=2002
                     35: # 1/4 Gerd Kortemeyer
1.1       albertel   36: 
                     37: # Makes a table out of the previous attempts
1.2       albertel   38: # Inputs result_from_symbread, user, domain, course_id
1.16      harris41   39: # Reads in non-network-related .tab files
1.1       albertel   40: 
1.35      matthew    41: # POD header:
                     42: 
                     43: =head1 NAME
                     44: 
                     45: Apache::loncommon - pile of common routines
                     46: 
                     47: =head1 SYNOPSIS
                     48: 
                     49: Referenced by other mod_perl Apache modules.
                     50: 
                     51: Invocation:
                     52:  &Apache::loncommon::SUBROUTINENAME(ARGUMENTS);
                     53: 
                     54: =head1 INTRODUCTION
                     55: 
                     56: Common collection of used subroutines.  This collection helps remove
                     57: redundancy from other modules and increase efficiency of memory usage.
                     58: 
                     59: Current things done:
                     60: 
                     61:  Makes a table out of the previous homework attempts
                     62:  Inputs result_from_symbread, user, domain, course_id
                     63:  Reads in non-network-related .tab files
                     64: 
                     65: This is part of the LearningOnline Network with CAPA project
                     66: described at http://www.lon-capa.org.
                     67: 
1.38    ! albertel   68: =head2 General Subroutines
1.35      matthew    69: 
                     70: =over 4
                     71: 
                     72: =cut 
                     73: 
                     74: # End of POD header
1.1       albertel   75: package Apache::loncommon;
                     76: 
                     77: use strict;
1.22      www        78: use Apache::lonnet();
1.8       albertel   79: use POSIX qw(strftime);
1.1       albertel   80: use Apache::Constants qw(:common);
                     81: use Apache::lonmsg();
1.22      www        82: my $readit;
                     83: 
1.20      www        84: # ----------------------------------------------- Filetypes/Languages/Copyright
1.12      harris41   85: my %language;
                     86: my %cprtag;
                     87: my %fe; my %fd;
1.15      harris41   88: my %fc;
1.12      harris41   89: 
1.20      www        90: # -------------------------------------------------------------- Thesaurus data
1.21      www        91: my @therelated;
                     92: my @theword;
                     93: my @thecount;
                     94: my %theindex;
                     95: my $thetotalcount;
1.20      www        96: my $thefuzzy=2;
                     97: my $thethreshold=0.1/$thefuzzy;
                     98: my $theavecount;
                     99: 
1.12      harris41  100: # ----------------------------------------------------------------------- BEGIN
1.38    ! albertel  101: 
        !           102: =pod
        !           103: 
1.35      matthew   104: =item BEGIN() 
                    105: 
                    106: Initialize values from language.tab, copyright.tab, filetypes.tab,
                    107: and filecategories.tab.
                    108: 
                    109: =cut
                    110: # ----------------------------------------------------------------------- BEGIN
                    111: 
1.18      www       112: BEGIN {
1.22      www       113: 
                    114:     unless ($readit) {
1.12      harris41  115: # ------------------------------------------------------------------- languages
                    116:     {
                    117: 	my $fh=Apache::File->new($Apache::lonnet::perlvar{'lonTabDir'}.
                    118: 				 '/language.tab');
1.16      harris41  119: 	if ($fh) {
                    120: 	    while (<$fh>) {
                    121: 		next if /^\#/;
                    122: 		chomp;
                    123: 		my ($key,$val)=(split(/\s+/,$_,2));
                    124: 		$language{$key}=$val;
                    125: 	    }
1.12      harris41  126: 	}
                    127:     }
                    128: # ------------------------------------------------------------------ copyrights
                    129:     {
1.16      harris41  130: 	my $fh=Apache::File->new($Apache::lonnet::perlvar{'lonIncludes'}.
                    131: 				  '/copyright.tab');
                    132: 	if ($fh) {
                    133: 	    while (<$fh>) {
                    134: 		next if /^\#/;
                    135: 		chomp;
                    136: 		my ($key,$val)=(split(/\s+/,$_,2));
                    137: 		$cprtag{$key}=$val;
                    138: 	    }
1.12      harris41  139: 	}
                    140:     }
1.15      harris41  141: # ------------------------------------------------------------- file categories
                    142:     {
                    143: 	my $fh=Apache::File->new($Apache::lonnet::perlvar{'lonTabDir'}.
1.16      harris41  144: 				  '/filecategories.tab');
                    145: 	if ($fh) {
                    146: 	    while (<$fh>) {
                    147: 		next if /^\#/;
                    148: 		chomp;
                    149: 		my ($key,$val)=(split(/\s+/,$_,2));
                    150: 		push @{$fc{$key}},$val;
                    151: 	    }
1.15      harris41  152: 	}
                    153:     }
1.12      harris41  154: # ------------------------------------------------------------------ file types
                    155:     {
1.16      harris41  156: 	my $fh=Apache::File->new($Apache::lonnet::perlvar{'lonTabDir'}.
                    157: 	       '/filetypes.tab');
                    158: 	if ($fh) {
                    159:             while (<$fh>) {
                    160: 		next if (/^\#/);
                    161: 		chomp;
                    162: 		my ($ending,$emb,$descr)=split(/\s+/,$_,3);
                    163: 		if ($descr ne '') { 
                    164: 		    $fe{$ending}=lc($emb);
                    165: 		    $fd{$ending}=$descr;
                    166: 		}
1.12      harris41  167: 	    }
                    168: 	}
                    169:     }
1.20      www       170: # -------------------------------------------------------------- Thesaurus data
                    171:     {
                    172: 	my $fh=Apache::File->new($Apache::lonnet::perlvar{'lonTabDir'}.
                    173: 	       '/thesaurus.dat');
                    174: 	if ($fh) {
                    175:             while (<$fh>) {
                    176:                my ($tword,$tindex,$tcount,$trelated)=split(/\@/,$_);
                    177:                $theindex{$tword}=$tindex;
                    178:                $theword[$tindex]=$tword;
                    179:                $thecount[$tindex]=$tcount;
                    180:                $thetotalcount+=$tcount;
                    181:                $therelated[$tindex]=$trelated;
                    182: 	   }
                    183:         }
                    184:         $theavecount=$thetotalcount/$#thecount;
                    185:     }
1.22      www       186:     &Apache::lonnet::logthis(
                    187:               "<font color=yellow>INFO: Read file types and thesaurus</font>");
                    188:     $readit=1;
                    189: }
1.32      matthew   190:     
                    191: }
                    192: # ============================================================= END BEGIN BLOCK
1.36      matthew   193: 
                    194: =item linked_select_forms(...)
                    195: 
                    196: linked_select_forms returns a string containing a <script></script> block
                    197: and html for two <select> menus.  The select menus will be linked in that
                    198: changing the value of the first menu will result in new values being placed
                    199: in the second menu.  The values in the select menu will appear in alphabetical
                    200: order.
                    201: 
                    202: linked_select_forms takes the following ordered inputs:
                    203: 
                    204: =over 4
                    205: 
                    206: =item $formname, the name of the <form> tag
                    207: 
                    208: =item $middletext, the text which appears between the <select> tags
                    209: 
                    210: =item $firstdefault, the default value for the first menu
                    211: 
                    212: =item $firstselectname, the name of the first <select> tag
                    213: 
                    214: =item $secondselectname, the name of the second <select> tag
                    215: 
                    216: =item $hashref, a reference to a hash containing the data for the menus.
                    217: 
                    218: Below is an example of such a hash.  Only the 'text', 'default', and 
                    219: 'select2' keys must appear as stated.  keys(%menu) are the possible 
                    220: values for the first select menu.  The text that coincides with the 
                    221: first menu values is given in $menu{$choice1}->{'text'}.  The values 
                    222: and text for the second menu are given in the hash pointed to by 
                    223: $menu{$choice1}->{'select2'}.  
                    224: 
                    225:  my %menu = ( A1 => { text =>"Choice A1" ,
                    226:                       default => "B3",
                    227:                       select2 => { 
                    228:                           B1 => "Choice B1",
                    229:                           B2 => "Choice B2",
                    230:                           B3 => "Choice B3",
                    231:                           B4 => "Choice B4"
                    232:                           }
                    233:                   },
                    234:               A2 => { text =>"Choice A2" ,
                    235:                       default => "C2",
                    236:                       select2 => { 
                    237:                           C1 => "Choice C1",
                    238:                           C2 => "Choice C2",
                    239:                           C3 => "Choice C3"
                    240:                           }
                    241:                   },
                    242:               A3 => { text =>"Choice A3" ,
                    243:                       default => "D6",
                    244:                       select2 => { 
                    245:                           D1 => "Choice D1",
                    246:                           D2 => "Choice D2",
                    247:                           D3 => "Choice D3",
                    248:                           D4 => "Choice D4",
                    249:                           D5 => "Choice D5",
                    250:                           D6 => "Choice D6",
                    251:                           D7 => "Choice D7"
                    252:                           }
                    253:                   }
                    254:               );
                    255: 
                    256: =back
                    257: 
                    258: =cut
                    259: 
                    260: # ------------------------------------------------
                    261: 
                    262: sub linked_select_forms {
                    263:     my ($formname,
                    264:         $middletext,
                    265:         $firstdefault,
                    266:         $firstselectname,
                    267:         $secondselectname, 
                    268:         $hashref
                    269:         ) = @_;
                    270:     my $second = "document.$formname.$secondselectname";
                    271:     my $first = "document.$formname.$firstselectname";
                    272:     # output the javascript to do the changing
                    273:     my $result = '';
                    274:     $result.="<script>\n";
                    275:     $result.="var select2data = new Object();\n";
                    276:     $" = '","';
                    277:     my $debug = '';
                    278:     foreach my $s1 (sort(keys(%$hashref))) {
                    279:         $result.="select2data.d_$s1 = new Object();\n";        
                    280:         $result.="select2data.d_$s1.def = new String('".
                    281:             $hashref->{$s1}->{'default'}."');\n";
                    282:         $result.="select2data.d_$s1.values = new Array(";        
                    283:         my @s2values = sort(keys( %{ $hashref->{$s1}->{'select2'} } ));
                    284:         $result.="\"@s2values\");\n";
                    285:         $result.="select2data.d_$s1.texts = new Array(";        
                    286:         my @s2texts;
                    287:         foreach my $value (@s2values) {
                    288:             push @s2texts, $hashref->{$s1}->{'select2'}->{$value};
                    289:         }
                    290:         $result.="\"@s2texts\");\n";
                    291:     }
                    292:     $"=' ';
                    293:     $result.= <<"END";
                    294: 
                    295: function select1_changed() {
                    296:     // Determine new choice
                    297:     var newvalue = "d_" + $first.value;
                    298:     // update select2
                    299:     var values     = select2data[newvalue].values;
                    300:     var texts      = select2data[newvalue].texts;
                    301:     var select2def = select2data[newvalue].def;
                    302:     var i;
                    303:     // out with the old
                    304:     for (i = 0; i < $second.options.length; i++) {
                    305:         $second.options[i] = null;
                    306:     }
                    307:     // in with the nuclear
                    308:     for (i=0;i<values.length; i++) {
                    309:         $second.options[i] = new Option(values[i]);
                    310:         $second.options[i].text = texts[i];
                    311:         if (values[i] == select2def) {
                    312:             $second.options[i].selected = true;
                    313:         }
                    314:     }
                    315: }
                    316: </script>
                    317: END
                    318:     # output the initial values for the selection lists
                    319:     $result .= "<select size=\"1\" name=\"$firstselectname\" onchange=\"select1_changed()\">\n";
                    320:     foreach my $value (sort(keys(%$hashref))) {
                    321:         $result.="    <option value=\"$value\" ";
                    322:         $result.=" selected=\"true\" " if ($value eq $firstdefault);
                    323:         $result.=">$hashref->{$value}->{'text'}</option>\n";
                    324:     }
                    325:     $result .= "</select>\n";
                    326:     my %select2 = %{$hashref->{$firstdefault}->{'select2'}};
                    327:     $result .= $middletext;
                    328:     $result .= "<select size=\"1\" name=\"$secondselectname\">\n";
                    329:     my $seconddefault = $hashref->{$firstdefault}->{'default'};
                    330:     foreach my $value (sort(keys(%select2))) {
                    331:         $result.="    <option value=\"$value\" ";        
                    332:         $result.=" selected=\"true\" " if ($value eq $seconddefault);
                    333:         $result.=">$select2{$value}</option>\n";
                    334:     }
                    335:     $result .= "</select>\n";
                    336:     #    return $debug;
                    337:     return $result;
                    338: }   #  end of sub linked_select_forms {
                    339: 
1.33      matthew   340: ###############################################################
1.37      matthew   341: 
                    342: =item csv_translate($text) 
                    343: 
                    344: Translate $text to allow it to be output as a 'comma seperated values' 
                    345: format.
                    346: 
                    347: =cut
                    348: 
                    349: sub csv_translate {
                    350:     my $text = shift;
                    351:     $text =~ s/\"/\"\"/g;
                    352:     $text =~ s/\n//g;
                    353:     return $text;
                    354: }
                    355: 
                    356: ###############################################################
                    357: 
                    358: ###############################################################
1.33      matthew   359: ##        Home server <option> list generating code          ##
                    360: ###############################################################
1.35      matthew   361: #-------------------------------------------
                    362: 
                    363: =item get_domains()
                    364: 
                    365: Returns an array containing each of the domains listed in the hosts.tab
                    366: file.
                    367: 
                    368: =cut
                    369: 
                    370: #-------------------------------------------
1.34      matthew   371: sub get_domains {
                    372:     # The code below was stolen from "The Perl Cookbook", p 102, 1st ed.
                    373:     my @domains;
                    374:     my %seen;
                    375:     foreach (sort values(%Apache::lonnet::hostdom)) {
                    376:         push (@domains,$_) unless $seen{$_}++;
                    377:     }
                    378:     return @domains;
                    379: }
                    380: 
1.35      matthew   381: #-------------------------------------------
                    382: 
                    383: =item select_dom_form($defdom,$name)
                    384: 
                    385: Returns a string containing a <select name='$name' size='1'> form to 
                    386: allow a user to select the domain to preform an operation in.  
                    387: See loncreateuser.pm for an example invocation and use.
                    388: 
                    389: =cut
                    390: 
                    391: #-------------------------------------------
1.34      matthew   392: sub select_dom_form {
                    393:     my ($defdom,$name) = @_;
                    394:     my @domains = get_domains();
                    395:     my $selectdomain = "<select name=\"$name\" size=\"1\">\n";
                    396:     foreach (@domains) {
                    397:         $selectdomain.="<option value=\"$_\" ".
                    398:             ($_ eq $defdom ? 'selected' : '').
                    399:                 ">$_</option>\n";
                    400:     }
                    401:     $selectdomain.="</select>";
                    402:     return $selectdomain;
                    403: }
                    404: 
1.35      matthew   405: #-------------------------------------------
                    406: 
                    407: =item get_home_servers($domain)
                    408: 
                    409: Returns a hash which contains keys like '103l3' and values like 
                    410: 'kirk.lite.msu.edu'.  All of the keys will be for machines in the
                    411: given $domain.
                    412: 
                    413: =cut
                    414: 
                    415: #-------------------------------------------
1.33      matthew   416: sub get_home_servers {
                    417:     my $domain = shift;
                    418:     my %home_servers;
                    419:     foreach (keys(%Apache::lonnet::libserv)) {
                    420:         if ($Apache::lonnet::hostdom{$_} eq $domain) {
                    421:             $home_servers{$_} = $Apache::lonnet::hostname{$_};
                    422:         }
                    423:     }
                    424:     return %home_servers;
                    425: }
                    426: 
1.35      matthew   427: #-------------------------------------------
                    428: 
                    429: =item home_server_option_list($domain)
                    430: 
                    431: returns a string which contains an <option> list to be used in a 
                    432: <select> form input.  See loncreateuser.pm for an example.
                    433: 
                    434: =cut
                    435: 
                    436: #-------------------------------------------
1.33      matthew   437: sub home_server_option_list {
                    438:     my $domain = shift;
                    439:     my %servers = &get_home_servers($domain);
                    440:     my $result = '';
                    441:     foreach (sort keys(%servers)) {
                    442:         $result.=
                    443:             '<option value="'.$_.'">'.$_.' '.$servers{$_}."</option>\n";
                    444:     }
                    445:     return $result;
                    446: }
                    447: ###############################################################
                    448: ##    End of home server <option> list generating code       ##
                    449: ###############################################################
1.32      matthew   450: 
                    451: ###############################################################
                    452: ##    Authentication changing form generation subroutines    ##
                    453: ###############################################################
                    454: ##
                    455: ## All of the authform_xxxxxxx subroutines take their inputs in a
                    456: ## hash, and have reasonable default values.
                    457: ##
                    458: ##    formname = the name given in the <form> tag.
1.35      matthew   459: #-------------------------------------------
                    460: 
                    461: =item authform_xxxxxx
                    462: 
                    463: The authform_xxxxxx subroutines provide javascript and html forms which 
                    464: handle some of the conveniences required for authentication forms.  
                    465: This is not an optimal method, but it works.  
                    466: 
                    467: See loncreateuser.pm for invocation and use examples.
                    468: 
                    469: =over 4
                    470: 
                    471: =item authform_header
                    472: 
                    473: =item authform_authorwarning
                    474: 
                    475: =item authform_nochange
                    476: 
                    477: =item authform_kerberos
                    478: 
                    479: =item authform_internal
                    480: 
                    481: =item authform_filesystem
                    482: 
                    483: =back
                    484: 
                    485: =cut
                    486: 
                    487: #-------------------------------------------
1.32      matthew   488: sub authform_header{  
                    489:     my %in = (
                    490:         formname => 'cu',
                    491:         kerb_def_dom => 'MSU.EDU',
                    492:         @_,
                    493:     );
                    494:     $in{'formname'} = 'document.' . $in{'formname'};
                    495:     my $result='';
                    496:     $result.=<<"END";
                    497: var current = new Object();
                    498: current.radiovalue = 'nochange';
                    499: current.argfield = null;
                    500: 
                    501: function changed_radio(choice,currentform) {
                    502:     var choicearg = choice + 'arg';
                    503:     // If a radio button in changed, we need to change the argfield
                    504:     if (current.radiovalue != choice) {
                    505:         current.radiovalue = choice;
                    506:         if (current.argfield != null) {
                    507:             currentform.elements[current.argfield].value = '';
                    508:         }
                    509:         if (choice == 'nochange') {
                    510:             current.argfield = null;
                    511:         } else {
                    512:             current.argfield = choicearg;
                    513:             switch(choice) {
                    514:                 case 'krb': 
                    515:                     currentform.elements[current.argfield].value = 
                    516:                         "$in{'kerb_def_dom'}";
                    517:                 break;
                    518:               default:
                    519:                 break;
                    520:             }
                    521:         }
                    522:     }
                    523:     return;
                    524: }
1.22      www       525: 
1.32      matthew   526: function changed_text(choice,currentform) {
                    527:     var choicearg = choice + 'arg';
                    528:     if (currentform.elements[choicearg].value !='') {
                    529:         switch (choice) {
                    530:             case 'krb': currentform.elements[choicearg].value =
                    531:                 currentform.elements[choicearg].value.toUpperCase();
                    532:                 break;
                    533:             default:
                    534:         }
                    535:         // clear old field
                    536:         if ((current.argfield != choicearg) && (current.argfield != null)) {
                    537:             currentform.elements[current.argfield].value = '';
                    538:         }
                    539:         current.argfield = choicearg;
                    540:     }
                    541:     set_auth_radio_buttons(choice,currentform);
                    542:     return;
1.20      www       543: }
1.32      matthew   544: 
                    545: function set_auth_radio_buttons(newvalue,currentform) {
                    546:     var i=0;
                    547:     while (i < currentform.login.length) {
                    548:         if (currentform.login[i].value == newvalue) { break; }
                    549:         i++;
                    550:     }
                    551:     if (i == currentform.login.length) {
                    552:         return;
                    553:     }
                    554:     current.radiovalue = newvalue;
                    555:     currentform.login[i].checked = true;
                    556:     return;
                    557: }
                    558: END
                    559:     return $result;
                    560: }
                    561: 
                    562: sub authform_authorwarning{
                    563:     my $result='';
                    564:     $result=<<"END";
                    565: <i>As a general rule, only authors or co-authors should be filesystem
                    566: authenticated (which allows access to the server filesystem).</i>
                    567: END
                    568:     return $result;
                    569: }
                    570: 
                    571: sub authform_nochange{  
                    572:     my %in = (
                    573:               formname => 'document.cu',
                    574:               kerb_def_dom => 'MSU.EDU',
                    575:               @_,
                    576:           );
                    577:     my $result='';
                    578:     $result.=<<"END";
                    579: <input type="radio" name="login" value="nochange" checked="checked"
                    580:        onclick="javascript:changed_radio('nochange',$in{'formname'});">
                    581: Do not change login data
                    582: END
                    583:     return $result;
                    584: }
                    585: 
                    586: sub authform_kerberos{  
                    587:     my %in = (
                    588:               formname => 'document.cu',
                    589:               kerb_def_dom => 'MSU.EDU',
                    590:               @_,
                    591:               );
                    592:     my $result='';
                    593:     $result.=<<"END";
                    594: <input type="radio" name="login" value="krb" 
                    595:        onclick="javascript:changed_radio('krb',$in{'formname'});"
                    596:        onchange="javascript:changed_radio('krb',$in{'formname'});">
                    597: Kerberos authenticated with domain
                    598: <input type="text" size="10" name="krbarg" value=""
                    599:        onchange="javascript:changed_text('krb',$in{'formname'});">
                    600: END
                    601:     return $result;
                    602: }
                    603: 
                    604: sub authform_internal{  
                    605:     my %args = (
                    606:                 formname => 'document.cu',
                    607:                 kerb_def_dom => 'MSU.EDU',
                    608:                 @_,
                    609:                 );
                    610:     my $result='';
                    611:     $result.=<<"END";
                    612: <input type="radio" name="login" value="int"
                    613:        onchange="javascript:changed_radio('int',$args{'formname'});"
                    614:        onclick="javascript:changed_radio('int',$args{'formname'});">
                    615: Internally authenticated (with initial password 
                    616: <input type="text" size="10" name="intarg" value=""
                    617:        onchange="javascript:changed_text('int',$args{'formname'});">
                    618: END
                    619:     return $result;
                    620: }
                    621: 
                    622: sub authform_local{  
                    623:     my %in = (
                    624:               formname => 'document.cu',
                    625:               kerb_def_dom => 'MSU.EDU',
                    626:               @_,
                    627:               );
                    628:     my $result='';
                    629:     $result.=<<"END";
                    630: <input type="radio" name="login" value="loc"
                    631:        onchange="javascript:changed_radio('loc',$in{'formname'});"
                    632:        onclick="javascript:changed_radio('loc',$in{'formname'});"> 
                    633: Local Authentication with argument
                    634: <input type="text" size="10" name="locarg" value=""
                    635:        onchange="javascript:changed_text('loc',$in{'formname'});">
                    636: END
                    637:     return $result;
                    638: }
                    639: 
                    640: sub authform_filesystem{  
                    641:     my %in = (
                    642:               formname => 'document.cu',
                    643:               kerb_def_dom => 'MSU.EDU',
                    644:               @_,
                    645:               );
                    646:     my $result='';
                    647:     $result.=<<"END";
                    648: <input type="radio" name="login" value="fsys" 
                    649:        onchange="javascript:changed_radio('fsys',$in{'formname'});"
                    650:        onclick="javascript:changed_radio('fsys',$in{'formname'});"> 
                    651: Filesystem authenticated (with initial password 
                    652: <input type="text" size="10" name="fsysarg" value=""
                    653:        onchange="javascript:changed_text('fsys',$in{'formname'});">
                    654: END
                    655:     return $result;
                    656: }
                    657: 
                    658: ###############################################################
                    659: ##   End Authentication changing form generation functions   ##
                    660: ###############################################################
                    661: 
1.20      www       662: 
                    663: 
                    664: # ---------------------------------------------------------- Is this a keyword?
                    665: 
                    666: sub keyword {
                    667:     my $newword=shift;
                    668:     $newword=~s/\W//g;
                    669:     $newword=~tr/A-Z/a-z/;
                    670:     my $tindex=$theindex{$newword};
                    671:     if ($tindex) {
                    672:         if ($thecount[$tindex]>$theavecount) {
                    673:            return 1;
                    674:         }
                    675:     }
                    676:     return 0;
                    677: }
                    678: # -------------------------------------------------------- Return related words
                    679: 
                    680: sub related {
                    681:     my $newword=shift;
                    682:     $newword=~s/\W//g;
                    683:     $newword=~tr/A-Z/a-z/;
                    684:     my $tindex=$theindex{$newword};
                    685:     if ($tindex) {
                    686:         my %found=();
                    687:         foreach (split(/\,/,$therelated[$tindex])) {
                    688: # - Related word found
                    689:             my ($ridx,$rcount)=split(/\:/,$_);
                    690: # - Direct relation index
                    691:             my $directrel=$rcount/$thecount[$tindex];
                    692:             if ($directrel>$thethreshold) {
                    693:                foreach (split(/\,/,$therelated[$ridx])) {
                    694:                   my ($rridx,$rrcount)=split(/\:/,$_);
                    695:                   if ($rridx==$tindex) {
                    696: # - Determine reverse relation index
                    697:                      my $revrel=$rrcount/$thecount[$ridx];
                    698: # - Calculate full index
                    699:                      $found{$ridx}=$directrel*$revrel;
                    700:                      if ($found{$ridx}>$thethreshold) {
                    701:                         foreach (split(/\,/,$therelated[$ridx])) {
                    702:                             my ($rrridx,$rrrcount)=split(/\:/,$_);
                    703:                             unless ($found{$rrridx}) {
                    704:                                my $revrevrel=$rrrcount/$thecount[$ridx];
                    705:                                if (
                    706:                           $directrel*$revrel*$revrevrel>$thethreshold
                    707:                                ) {
                    708:                                   $found{$rrridx}=
                    709:                                        $directrel*$revrel*$revrevrel;
                    710:                                }
                    711:                             }
                    712:                         }
                    713:                      }
                    714:                   }
                    715:                }
                    716:             }
                    717:         }
                    718:     }
                    719:     return ();
1.14      harris41  720: }
                    721: 
                    722: # ---------------------------------------------------------------- Language IDs
                    723: sub languageids {
1.16      harris41  724:     return sort(keys(%language));
1.14      harris41  725: }
                    726: 
                    727: # -------------------------------------------------------- Language Description
                    728: sub languagedescription {
1.16      harris41  729:     return $language{shift(@_)};
1.14      harris41  730: }
                    731: 
                    732: # --------------------------------------------------------------- Copyright IDs
                    733: sub copyrightids {
1.16      harris41  734:     return sort(keys(%cprtag));
1.14      harris41  735: }
                    736: 
                    737: # ------------------------------------------------------- Copyright Description
                    738: sub copyrightdescription {
1.16      harris41  739:     return $cprtag{shift(@_)};
1.14      harris41  740: }
                    741: 
                    742: # ------------------------------------------------------------- File Categories
                    743: sub filecategories {
1.16      harris41  744:     return sort(keys(%fc));
1.15      harris41  745: }
1.14      harris41  746: 
1.17      harris41  747: # -------------------------------------- File Types within a specified category
1.15      harris41  748: sub filecategorytypes {
1.16      harris41  749:     return @{$fc{lc(shift(@_))}};
1.14      harris41  750: }
                    751: 
                    752: # ------------------------------------------------------------------ File Types
                    753: sub fileextensions {
1.16      harris41  754:     return sort(keys(%fe));
1.14      harris41  755: }
                    756: 
                    757: # ------------------------------------------------------------- Embedding Style
                    758: sub fileembstyle {
1.16      harris41  759:     return $fe{lc(shift(@_))};
1.14      harris41  760: }
                    761: 
                    762: # ------------------------------------------------------------ Description Text
                    763: sub filedescription {
1.16      harris41  764:     return $fd{lc(shift(@_))};
                    765: }
                    766: 
                    767: # ------------------------------------------------------------ Description Text
                    768: sub filedescriptionex {
                    769:     my $ex=shift;
                    770:     return '.'.$ex.' '.$fd{lc($ex)};
1.12      harris41  771: }
1.1       albertel  772: 
                    773: sub get_previous_attempt {
1.2       albertel  774:   my ($symb,$username,$domain,$course)=@_;
1.1       albertel  775:   my $prevattempts='';
                    776:   if ($symb) {
1.3       albertel  777:     my (%returnhash)=
                    778:       &Apache::lonnet::restore($symb,$course,$domain,$username);
1.1       albertel  779:     if ($returnhash{'version'}) {
                    780:       my %lasthash=();
                    781:       my $version;
                    782:       for ($version=1;$version<=$returnhash{'version'};$version++) {
1.19      harris41  783:         foreach (sort(split(/\:/,$returnhash{$version.':keys'}))) {
1.1       albertel  784: 	  $lasthash{$_}=$returnhash{$version.':'.$_};
1.19      harris41  785:         }
1.1       albertel  786:       }
                    787:       $prevattempts='<table border=2></tr><th>History</th>';
1.16      harris41  788:       foreach (sort(keys %lasthash)) {
1.31      albertel  789: 	my ($ign,@parts) = split(/\./,$_);
1.38    ! albertel  790: 	if ($#parts > 0) {
1.31      albertel  791: 	  my $data=$parts[-1];
                    792: 	  pop(@parts);
                    793: 	  $prevattempts.='<th>Part '.join('.',@parts).'<br />'.$data.'</th>';
                    794: 	} else {
1.38    ! albertel  795: 	  if ($#parts == 0) {
        !           796: 	    $prevattempts.='<th>'.$parts[0].'</th>';
        !           797: 	  } else {
        !           798: 	    $prevattempts.='<th>'.$ign.'</th>';
        !           799: 	  }
1.31      albertel  800: 	}
1.16      harris41  801:       }
1.1       albertel  802:       for ($version=1;$version<=$returnhash{'version'};$version++) {
                    803:         $prevattempts.='</tr><tr><th>Attempt '.$version.'</th>';
1.16      harris41  804:         foreach (sort(keys %lasthash)) {
1.5       albertel  805: 	  my $value;
                    806: 	  if ($_ =~ /timestamp/) {
                    807: 	    $value=scalar(localtime($returnhash{$version.':'.$_}));
                    808: 	  } else {
                    809: 	    $value=$returnhash{$version.':'.$_};
                    810: 	  }
                    811: 	  $prevattempts.='<td>'.$value.'</td>';   
1.16      harris41  812:         }
1.1       albertel  813:       }
                    814:       $prevattempts.='</tr><tr><th>Current</th>';
1.16      harris41  815:       foreach (sort(keys %lasthash)) {
1.5       albertel  816: 	my $value;
                    817: 	if ($_ =~ /timestamp/) {
                    818: 	  $value=scalar(localtime($lasthash{$_}));
                    819: 	} else {
                    820: 	  $value=$lasthash{$_};
                    821: 	}
                    822: 	$prevattempts.='<td>'.$value.'</td>';
1.16      harris41  823:       }
1.1       albertel  824:       $prevattempts.='</tr></table>';
                    825:     } else {
                    826:       $prevattempts='Nothing submitted - no attempts.';
                    827:     }
                    828:   } else {
                    829:     $prevattempts='No data.';
                    830:   }
1.10      albertel  831: }
                    832: 
                    833: sub get_student_view {
                    834:   my ($symb,$username,$domain,$courseid) = @_;
                    835:   my ($map,$id,$feedurl) = split(/___/,$symb);
                    836:   my (%old,%moreenv);
                    837:   my @elements=('symb','courseid','domain','username');
                    838:   foreach my $element (@elements) {
                    839:     $old{$element}=$ENV{'form.grade_'.$element};
                    840:     $moreenv{'form.grade_'.$element}=eval '$'.$element #'
                    841:   }
1.11      albertel  842:   &Apache::lonnet::appenv(%moreenv);
                    843:   my $userview=&Apache::lonnet::ssi('/res/'.$feedurl);
                    844:   &Apache::lonnet::delenv('form.grade_');
                    845:   foreach my $element (@elements) {
                    846:     $ENV{'form.grade_'.$element}=$old{$element};
                    847:   }
                    848:   $userview=~s/\<body[^\>]*\>//gi;
                    849:   $userview=~s/\<\/body\>//gi;
                    850:   $userview=~s/\<html\>//gi;
                    851:   $userview=~s/\<\/html\>//gi;
                    852:   $userview=~s/\<head\>//gi;
                    853:   $userview=~s/\<\/head\>//gi;
                    854:   $userview=~s/action\s*\=/would_be_action\=/gi;
                    855:   return $userview;
                    856: }
                    857: 
                    858: sub get_student_answers {
                    859:   my ($symb,$username,$domain,$courseid) = @_;
                    860:   my ($map,$id,$feedurl) = split(/___/,$symb);
                    861:   my (%old,%moreenv);
                    862:   my @elements=('symb','courseid','domain','username');
                    863:   foreach my $element (@elements) {
                    864:     $old{$element}=$ENV{'form.grade_'.$element};
                    865:     $moreenv{'form.grade_'.$element}=eval '$'.$element #'
                    866:   }
                    867:   $moreenv{'form.grade_target'}='answer';
1.10      albertel  868:   &Apache::lonnet::appenv(%moreenv);
                    869:   my $userview=&Apache::lonnet::ssi('/res/'.$feedurl);
                    870:   &Apache::lonnet::delenv('form.grade_');
                    871:   foreach my $element (@elements) {
                    872:     $ENV{'form.grade_'.$element}=$old{$element};
                    873:   }
                    874:   return $userview;
1.1       albertel  875: }
1.37      matthew   876: 
                    877: ###############################################
                    878: 
                    879: ###############################################
1.1       albertel  880: 
1.6       albertel  881: sub get_unprocessed_cgi {
1.25      albertel  882:   my ($query,$possible_names)= @_;
1.26      matthew   883:   # $Apache::lonxml::debug=1;
1.16      harris41  884:   foreach (split(/&/,$query)) {
1.6       albertel  885:     my ($name, $value) = split(/=/,$_);
1.25      albertel  886:     $name = &Apache::lonnet::unescape($name);
                    887:     if (!defined($possible_names) || (grep {$_ eq $name} @$possible_names)) {
                    888:       $value =~ tr/+/ /;
                    889:       $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/eg;
                    890:       &Apache::lonxml::debug("Seting :$name: to :$value:");
1.30      albertel  891:       unless (defined($ENV{'form.'.$name})) { &add_to_env('form.'.$name,$value) };
1.25      albertel  892:     }
1.16      harris41  893:   }
1.6       albertel  894: }
                    895: 
1.7       albertel  896: sub cacheheader {
1.23      www       897:   unless ($ENV{'request.method'} eq 'GET') { return ''; }
1.8       albertel  898:   my $date=strftime("%a, %d %b %Y %H:%M:%S GMT",gmtime);
1.7       albertel  899:   my $output .='<meta HTTP-EQUIV="Expires" CONTENT="'.$date.'" />
                    900:                 <meta HTTP-EQUIV="Cache-control" CONTENT="no-cache" />
                    901:                 <meta HTTP-EQUIV="Pragma" CONTENT="no-cache" />';
                    902:   return $output;
                    903: }
                    904: 
1.9       albertel  905: sub no_cache {
                    906:   my ($r) = @_;
1.23      www       907:   unless ($ENV{'request.method'} eq 'GET') { return ''; }
1.24      albertel  908:   #my $date=strftime("%a, %d %b %Y %H:%M:%S GMT",gmtime);
1.9       albertel  909:   $r->no_cache(1);
                    910:   $r->header_out("Pragma" => "no-cache");
1.24      albertel  911:   #$r->header_out("Expires" => $date);
1.9       albertel  912: }
1.25      albertel  913: 
                    914: sub add_to_env {
                    915:   my ($name,$value)=@_;
1.28      albertel  916:   if (defined($ENV{$name})) {
1.27      albertel  917:     if (ref($ENV{$name})) {
1.25      albertel  918:       #already have multiple values
                    919:       push(@{ $ENV{$name} },$value);
                    920:     } else {
                    921:       #first time seeing multiple values, convert hash entry to an arrayref
                    922:       my $first=$ENV{$name};
                    923:       undef($ENV{$name});
                    924:       push(@{ $ENV{$name} },$first,$value);
                    925:     }
                    926:   } else {
                    927:     $ENV{$name}=$value;
                    928:   }
1.31      albertel  929: }
                    930: 
1.38    ! albertel  931: =pod
        !           932: 
        !           933: =back
        !           934: 
        !           935: =head2 CSV Upload/Handling functions
1.31      albertel  936: 
1.38    ! albertel  937: =over 4
        !           938: 
        !           939: =item  upfile_store($r)
        !           940: 
        !           941: Store uploaded file, $r should be the HTTP Request object,
        !           942: needs $ENV{'form.upfile'}
        !           943: returns $datatoken to be put into hidden field
        !           944: 
        !           945: =cut
1.31      albertel  946: 
                    947: sub upfile_store {
                    948:     my $r=shift;
                    949:     $ENV{'form.upfile'}=~s/\r/\n/gs;
                    950:     $ENV{'form.upfile'}=~s/\f/\n/gs;
                    951:     $ENV{'form.upfile'}=~s/\n+/\n/gs;
                    952:     $ENV{'form.upfile'}=~s/\n+$//gs;
                    953: 
                    954:     my $datatoken=$ENV{'user.name'}.'_'.$ENV{'user.domain'}.
                    955: 	'_enroll_'.$ENV{'request.course.id'}.'_'.time.'_'.$$;
                    956:     {
                    957: 	my $fh=Apache::File->new('>'.$r->dir_config('lonDaemons').
                    958: 				 '/tmp/'.$datatoken.'.tmp');
                    959: 	print $fh $ENV{'form.upfile'};
                    960:     }
                    961:     return $datatoken;
                    962: }
                    963: 
1.38    ! albertel  964: =item load_tmp_file($r)
        !           965: 
        !           966: Load uploaded file from tmp, $r should be the HTTP Request object,
        !           967: needs $ENV{'form.datatoken'},
        !           968: sets $ENV{'form.upfile'} to the contents of the file
        !           969: 
        !           970: =cut
1.31      albertel  971: 
                    972: sub load_tmp_file {
                    973:     my $r=shift;
                    974:     my @studentdata=();
                    975:     {
                    976: 	my $fh;
                    977: 	if ($fh=Apache::File->new($r->dir_config('lonDaemons').
                    978: 				  '/tmp/'.$ENV{'form.datatoken'}.'.tmp')) {
                    979: 	    @studentdata=<$fh>;
                    980: 	}
                    981:     }
                    982:     $ENV{'form.upfile'}=join('',@studentdata);
                    983: }
                    984: 
1.38    ! albertel  985: =item upfile_record_sep()
        !           986: 
        !           987: Separate uploaded file into records
        !           988: returns array of records,
        !           989: needs $ENV{'form.upfile'} and $ENV{'form.upfiletype'}
        !           990: 
        !           991: =cut
1.31      albertel  992: 
                    993: sub upfile_record_sep {
                    994:     if ($ENV{'form.upfiletype'} eq 'xml') {
                    995:     } else {
                    996: 	return split(/\n/,$ENV{'form.upfile'});
                    997:     }
                    998: }
                    999: 
1.38    ! albertel 1000: =item record_sep($record)
        !          1001: 
        !          1002: Separate a record into fields $record should be an item from the upfile_record_sep(), needs $ENV{'form.upfiletype'}
        !          1003: 
        !          1004: =cut
        !          1005: 
1.31      albertel 1006: sub record_sep {
                   1007:     my $record=shift;
                   1008:     my %components=();
                   1009:     if ($ENV{'form.upfiletype'} eq 'xml') {
                   1010:     } elsif ($ENV{'form.upfiletype'} eq 'space') {
                   1011:         my $i=0;
                   1012:         foreach (split(/\s+/,$record)) {
                   1013:             my $field=$_;
                   1014:             $field=~s/^(\"|\')//;
                   1015:             $field=~s/(\"|\')$//;
                   1016:             $components{$i}=$field;
                   1017:             $i++;
                   1018:         }
                   1019:     } elsif ($ENV{'form.upfiletype'} eq 'tab') {
                   1020:         my $i=0;
                   1021:         foreach (split(/\t+/,$record)) {
                   1022:             my $field=$_;
                   1023:             $field=~s/^(\"|\')//;
                   1024:             $field=~s/(\"|\')$//;
                   1025:             $components{$i}=$field;
                   1026:             $i++;
                   1027:         }
                   1028:     } else {
                   1029:         my @allfields=split(/\,/,$record);
                   1030:         my $i=0;
                   1031:         my $j;
                   1032:         for ($j=0;$j<=$#allfields;$j++) {
                   1033:             my $field=$allfields[$j];
                   1034:             if ($field=~/^\s*(\"|\')/) {
                   1035: 		my $delimiter=$1;
                   1036:                 while (($field!~/$delimiter$/) && ($j<$#allfields)) {
                   1037: 		    $j++;
                   1038: 		    $field.=','.$allfields[$j];
                   1039: 		}
                   1040:                 $field=~s/^\s*$delimiter//;
                   1041:                 $field=~s/$delimiter\s*$//;
                   1042:             }
                   1043:             $components{$i}=$field;
                   1044: 	    $i++;
                   1045:         }
                   1046:     }
                   1047:     return %components;
                   1048: }
                   1049: 
1.38    ! albertel 1050: =item upfile_select_html()
        !          1051: 
        !          1052: return HTML code to select file and specify its type
        !          1053: 
        !          1054: =cut
        !          1055: 
1.31      albertel 1056: sub upfile_select_html {
                   1057:     return (<<'ENDUPFORM');
                   1058: <input type="file" name="upfile" size="50">
                   1059: <br />Type: <select name="upfiletype">
                   1060: <option value="csv">CSV (comma separated values, spreadsheet)</option>
                   1061: <option value="space">Space separated</option>
                   1062: <option value="tab">Tabulator separated</option>
                   1063: <option value="xml">HTML/XML</option>
                   1064: </select>
                   1065: ENDUPFORM
                   1066: }
                   1067: 
1.38    ! albertel 1068: =item csv_print_samples($r,$records)
        !          1069: 
        !          1070: Prints a table of sample values from each column uploaded $r is an
        !          1071: Apache Request ref, $records is an arrayref from
        !          1072: &Apache::loncommon::upfile_record_sep
        !          1073: 
        !          1074: =cut
        !          1075: 
1.31      albertel 1076: sub csv_print_samples {
                   1077:     my ($r,$records) = @_;
                   1078:     my (%sone,%stwo,%sthree);
                   1079:     %sone=&record_sep($$records[0]);
                   1080:     if (defined($$records[1])) {%stwo=&record_sep($$records[1]);}
                   1081:     if (defined($$records[2])) {%sthree=&record_sep($$records[2]);}
                   1082: 
                   1083:     $r->print('Samples<br /><table border="2"><tr>');
                   1084:     foreach (sort({$a <=> $b} keys(%sone))) { $r->print('<th>Column&nbsp;'.($_+1).'</th>'); }
                   1085:     $r->print('</tr>');
                   1086:     foreach my $hash (\%sone,\%stwo,\%sthree) {
                   1087: 	$r->print('<tr>');
                   1088: 	foreach (sort({$a <=> $b} keys(%sone))) {
                   1089: 	    $r->print('<td>');
                   1090: 	    if (defined($$hash{$_})) { $r->print($$hash{$_}); }
                   1091: 	    $r->print('</td>');
                   1092: 	}
                   1093: 	$r->print('</tr>');
                   1094:     }
                   1095:     $r->print('</tr></table><br />'."\n");
                   1096: }
                   1097: 
1.38    ! albertel 1098: =item csv_print_select_table($r,$records,$d)
        !          1099: 
        !          1100: Prints a table to create associations between values and table columns.
        !          1101: $r is an Apache Request ref,
        !          1102: $records is an arrayref from &Apache::loncommon::upfile_record_sep,
        !          1103: $d is an array of 2 element arrays (internal name, displayed name)
        !          1104: 
        !          1105: =cut
        !          1106: 
1.31      albertel 1107: sub csv_print_select_table {
                   1108:     my ($r,$records,$d) = @_;
                   1109:     my $i=0;my %sone;
                   1110:     %sone=&record_sep($$records[0]);
                   1111:     $r->print('Associate columns with student attributes.'."\n".
                   1112: 	     '<table border="2"><tr><th>Attribute</th><th>Column</th></tr>'."\n");
                   1113:     foreach (@$d) {
                   1114: 	my ($value,$display)=@{ $_ };
                   1115: 	$r->print('<tr><td>'.$display.'</td>');
                   1116: 
                   1117: 	$r->print('<td><select name=f'.$i.
1.32      matthew  1118: 		  ' onchange="javascript:flip(this.form,'.$i.');">');
1.31      albertel 1119: 	$r->print('<option value="none"></option>');
                   1120: 	foreach (sort({$a <=> $b} keys(%sone))) {
                   1121: 	    $r->print('<option value="'.$_.'">Column '.($_+1).'</option>');
                   1122: 	}
                   1123: 	$r->print('</select></td></tr>'."\n");
                   1124: 	$i++;
                   1125:     }
                   1126:     $i--;
                   1127:     return $i;
                   1128: }
                   1129: 
1.38    ! albertel 1130: =item csv_samples_select_table($r,$records,$d)
        !          1131: 
        !          1132: Prints a table of sample values from the upload and can make associate samples to internal names.
        !          1133: 
        !          1134: $r is an Apache Request ref,
        !          1135: $records is an arrayref from &Apache::loncommon::upfile_record_sep,
        !          1136: $d is an array of 2 element arrays (internal name, displayed name)
        !          1137: 
        !          1138: =cut
        !          1139: 
1.31      albertel 1140: sub csv_samples_select_table {
                   1141:     my ($r,$records,$d) = @_;
                   1142:     my %sone; my %stwo; my %sthree;
                   1143:     my $i=0;
                   1144: 
                   1145:     $r->print('<table border=2><tr><th>Field</th><th>Samples</th></tr>');
                   1146:     %sone=&record_sep($$records[0]);
                   1147:     if (defined($$records[1])) {%stwo=&record_sep($$records[1]);}
                   1148:     if (defined($$records[2])) {%sthree=&record_sep($$records[2]);}
                   1149: 
                   1150:     foreach (sort keys %sone) {
                   1151: 	$r->print('<tr><td><select name=f'.$i.
1.32      matthew  1152: 		  ' onchange="javascript:flip(this.form,'.$i.');">');
1.31      albertel 1153: 	foreach (@$d) {
                   1154: 	    my ($value,$display)=@{ $_ };
                   1155: 	    $r->print('<option value='.$value.'>'.$display.'</option>');
                   1156: 	}
                   1157: 	$r->print('</select></td><td>');
                   1158: 	if (defined($sone{$_})) { $r->print($sone{$_}."</br>\n"); }
                   1159: 	if (defined($stwo{$_})) { $r->print($stwo{$_}."</br>\n"); }
                   1160: 	if (defined($sthree{$_})) { $r->print($sthree{$_}."</br>\n"); }
                   1161: 	$r->print('</td></tr>');
                   1162: 	$i++;
                   1163:     }
                   1164:     $i--;
                   1165:     return($i);
1.25      albertel 1166: }
1.1       albertel 1167: 1;
                   1168: __END__;
1.17      harris41 1169: 
1.38    ! albertel 1170: =pod
        !          1171: 
        !          1172: =back
        !          1173: 
        !          1174: =head2 Access .tab File Data
        !          1175: 
        !          1176: =over 4
        !          1177: 
1.35      matthew  1178: =item languageids() 
1.17      harris41 1179: 
1.35      matthew  1180: returns list of all language ids
1.17      harris41 1181: 
1.35      matthew  1182: =item languagedescription() 
1.17      harris41 1183: 
1.35      matthew  1184: returns description of a specified language id
1.17      harris41 1185: 
1.35      matthew  1186: =item copyrightids() 
1.17      harris41 1187: 
1.35      matthew  1188: returns list of all copyrights
1.17      harris41 1189: 
1.35      matthew  1190: =item copyrightdescription() 
1.17      harris41 1191: 
1.35      matthew  1192: returns description of a specified copyright id
1.17      harris41 1193: 
1.35      matthew  1194: =item filecategories() 
1.17      harris41 1195: 
1.35      matthew  1196: returns list of all file categories
1.17      harris41 1197: 
1.35      matthew  1198: =item filecategorytypes() 
1.17      harris41 1199: 
1.35      matthew  1200: returns list of file types belonging to a given file
1.17      harris41 1201: category
                   1202: 
1.35      matthew  1203: =item fileembstyle() 
1.17      harris41 1204: 
1.35      matthew  1205: returns embedding style for a specified file type
1.17      harris41 1206: 
1.35      matthew  1207: =item filedescription() 
1.17      harris41 1208: 
1.35      matthew  1209: returns description for a specified file type
1.17      harris41 1210: 
1.35      matthew  1211: =item filedescriptionex() 
1.17      harris41 1212: 
1.35      matthew  1213: returns description for a specified file type with
1.17      harris41 1214: extra formatting
                   1215: 
1.38    ! albertel 1216: =back
        !          1217: 
        !          1218: =head2 Alternate Problem Views
        !          1219: 
        !          1220: =over 4
        !          1221: 
1.35      matthew  1222: =item get_previous_attempt() 
1.17      harris41 1223: 
1.35      matthew  1224: return string with previous attempt on problem
1.17      harris41 1225: 
1.35      matthew  1226: =item get_student_view() 
1.17      harris41 1227: 
1.35      matthew  1228: show a snapshot of what student was looking at
1.17      harris41 1229: 
1.35      matthew  1230: =item get_student_answers() 
1.17      harris41 1231: 
1.35      matthew  1232: show a snapshot of how student was answering problem
1.17      harris41 1233: 
1.38    ! albertel 1234: =back
        !          1235: 
        !          1236: =head2 HTTP Helper
        !          1237: 
        !          1238: =over 4
1.17      harris41 1239: 
1.38    ! albertel 1240: =item get_unprocessed_cgi($query,$possible_names)
        !          1241: 
        !          1242: Modify the %ENV hash to contain unprocessed CGI form parameters held in
        !          1243: $query.  The parameters listed in $possible_names (an array reference),
        !          1244: will be set in $ENV{'form.name'} if they do not already exist.
        !          1245: 
        !          1246: Typically called with $ENV{'QUERY_STRING'} as the first parameter.  
        !          1247: $possible_names is an ref to an array of form element names.  As an example:
        !          1248: get_unprocessed_cgi($ENV{'QUERY_STRING'},['uname','udom']);
        !          1249: will result in $ENV{'form.uname'} and $ENV{'form.udom'} being set.
1.17      harris41 1250: 
1.35      matthew  1251: =item cacheheader() 
1.17      harris41 1252: 
1.35      matthew  1253: returns cache-controlling header code
1.17      harris41 1254: 
1.35      matthew  1255: =item nocache() 
1.17      harris41 1256: 
1.35      matthew  1257: specifies header code to not have cache
1.25      albertel 1258: 
1.35      matthew  1259: =item add_to_env($name,$value) 
1.25      albertel 1260: 
1.35      matthew  1261: adds $name to the %ENV hash with value
1.25      albertel 1262: $value, if $name already exists, the entry is converted to an array
                   1263: reference and $value is added to the array.
1.17      harris41 1264: 
                   1265: =back
                   1266: 
                   1267: =cut

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>