Diff for /loncom/interface/loncommon.pm between versions 1.948.2.27 and 1.1107

version 1.948.2.27, 2011/03/04 01:32:00 version 1.1107, 2012/12/27 00:00:23
Line 70  use Apache::lonclonecourse(); Line 70  use Apache::lonclonecourse();
 use LONCAPA qw(:DEFAULT :match);  use LONCAPA qw(:DEFAULT :match);
 use DateTime::TimeZone;  use DateTime::TimeZone;
 use DateTime::Locale::Catalog;  use DateTime::Locale::Catalog;
   use Text::Aspell;
   use Authen::Captcha;
   use Captcha::reCAPTCHA;
   
 # ---------------------------------------------- Designs  # ---------------------------------------------- Designs
 use vars qw(%defaultdesign);  use vars qw(%defaultdesign);
Line 154  sub ssi_with_retries { Line 157  sub ssi_with_retries {
 # ----------------------------------------------- Filetypes/Languages/Copyright  # ----------------------------------------------- Filetypes/Languages/Copyright
 my %language;  my %language;
 my %supported_language;  my %supported_language;
   my %supported_codes;
   my %latex_language; # For choosing hyphenation in <transl..>
   my %latex_language_bykey; # for choosing hyphenation from metadata
 my %cprtag;  my %cprtag;
 my %scprtag;  my %scprtag;
 my %fe; my %fd; my %fm;  my %fe; my %fd; my %fm;
Line 186  BEGIN { Line 192  BEGIN {
             while (my $line = <$fh>) {              while (my $line = <$fh>) {
                 next if ($line=~/^\#/);                  next if ($line=~/^\#/);
                 chomp($line);                  chomp($line);
                 my ($key,$two,$country,$three,$enc,$val,$sup)=(split(/\t/,$line));                  my ($key,$code,$country,$three,$enc,$val,$sup,$latex)=(split(/\t/,$line));
                 $language{$key}=$val.' - '.$enc;                  $language{$key}=$val.' - '.$enc;
                 if ($sup) {                  if ($sup) {
                     $supported_language{$key}=$sup;                      $supported_language{$key}=$sup;
       $supported_codes{$key}   = $code;
                 }                  }
    if ($latex) {
       $latex_language_bykey{$key} = $latex;
       $latex_language{$code} = $latex;
    }
             }              }
             close($fh);              close($fh);
         }          }
Line 409  sub studentbrowser_javascript { Line 420  sub studentbrowser_javascript {
 <script type="text/javascript" language="Javascript">  <script type="text/javascript" language="Javascript">
 // <![CDATA[  // <![CDATA[
     var stdeditbrowser;      var stdeditbrowser;
     function openstdbrowser(formname,uname,udom,roleflag,ignorefilter,courseadvonly) {      function openstdbrowser(formname,uname,udom,clicker,roleflag,ignorefilter,courseadvonly) {
         var url = '/adm/pickstudent?';          var url = '/adm/pickstudent?';
         var filter;          var filter;
  if (!ignorefilter) {   if (!ignorefilter) {
Line 421  sub studentbrowser_javascript { Line 432  sub studentbrowser_javascript {
    }     }
         }          }
         url += 'form=' + formname + '&unameelement='+uname+          url += 'form=' + formname + '&unameelement='+uname+
                                     '&udomelement='+udom;                                      '&udomelement='+udom+
                                       '&clicker='+clicker;
  if (roleflag) { url+="&roles=1"; }   if (roleflag) { url+="&roles=1"; }
         if (courseadvonly) { url+="&courseadvonly=1"; }          if (courseadvonly) { url+="&courseadvonly=1"; }
         var title = 'Student_Browser';          var title = 'Student_Browser';
Line 435  sub studentbrowser_javascript { Line 447  sub studentbrowser_javascript {
 ENDSTDBRW  ENDSTDBRW
 }  }
   
   sub resourcebrowser_javascript {
      unless ($env{'request.course.id'}) { return ''; }
      return (<<'ENDRESBRW');
   <script type="text/javascript" language="Javascript">
   // <![CDATA[
       var reseditbrowser;
       function openresbrowser(formname,reslink) {
           var url = '/adm/pickresource?form='+formname+'&reslink='+reslink;
           var title = 'Resource_Browser';
           var options = 'scrollbars=1,resizable=1,menubar=0';
           options += ',width=700,height=500';
           reseditbrowser = open(url,title,options,'1');
           reseditbrowser.focus();
       }
   // ]]>
   </script>
   ENDRESBRW
   }
   
 sub selectstudent_link {  sub selectstudent_link {
    my ($form,$unameele,$udomele,$courseadvonly)=@_;     my ($form,$unameele,$udomele,$courseadvonly,$clickerid)=@_;
    my $callargs = "'".$form."','".$unameele."','".$udomele."'";     my $callargs = "'".&Apache::lonhtmlcommon::entity_encode($form)."','".
                         &Apache::lonhtmlcommon::entity_encode($unameele)."','".
                         &Apache::lonhtmlcommon::entity_encode($udomele)."'";
    if ($env{'request.course.id'}) {       if ($env{'request.course.id'}) {  
        if (!&Apache::lonnet::allowed('srm',$env{'request.course.id'})         if (!&Apache::lonnet::allowed('srm',$env{'request.course.id'})
    && !&Apache::lonnet::allowed('srm',$env{'request.course.id'}.     && !&Apache::lonnet::allowed('srm',$env{'request.course.id'}.
  '/'.$env{'request.course.sec'})) {   '/'.$env{'request.course.sec'})) {
    return '';     return '';
        }         }
          $callargs.=",'".&Apache::lonhtmlcommon::entity_encode($clickerid)."'";
        if ($courseadvonly)  {         if ($courseadvonly)  {
            $callargs .= ",'',1,1";             $callargs .= ",'',1,1";
        }         }
Line 452  sub selectstudent_link { Line 486  sub selectstudent_link {
               &mt('Select User').'</a></span>';                &mt('Select User').'</a></span>';
    }     }
    if ($env{'request.role'}=~/^(au|dc|su)/) {     if ($env{'request.role'}=~/^(au|dc|su)/) {
        $callargs .= ",1";          $callargs .= ",'',1"; 
        return '<span class="LC_nobreak">'.         return '<span class="LC_nobreak">'.
               '<a href="javascript:openstdbrowser('.$callargs.');">'.                '<a href="javascript:openstdbrowser('.$callargs.');">'.
               &mt('Select User').'</a></span>';                &mt('Select User').'</a></span>';
Line 460  sub selectstudent_link { Line 494  sub selectstudent_link {
    return '';     return '';
 }  }
   
   sub selectresource_link {
      my ($form,$reslink,$arg)=@_;
      
      my $callargs = "'".&Apache::lonhtmlcommon::entity_encode($form)."','".
                         &Apache::lonhtmlcommon::entity_encode($reslink)."'";
      unless ($env{'request.course.id'}) { return $arg; }
      return '<span class="LC_nobreak">'.
                 '<a href="javascript:openresbrowser('.$callargs.');">'.
                 $arg.'</a></span>';
   }
   
   
   
 sub authorbrowser_javascript {  sub authorbrowser_javascript {
     return <<"ENDAUTHORBRW";      return <<"ENDAUTHORBRW";
 <script type="text/javascript" language="JavaScript">  <script type="text/javascript" language="JavaScript">
Line 596  ENDJS Line 643  ENDJS
   
 }  }
   
   sub javascript_array_indexof {
       return <<ENDJS;
   <script type="text/javascript" language="JavaScript">
   // <![CDATA[
   
   if (!Array.prototype.indexOf) {
       Array.prototype.indexOf = function (searchElement /*, fromIndex */ ) {
           "use strict";
           if (this === void 0 || this === null) {
               throw new TypeError();
           }
           var t = Object(this);
           var len = t.length >>> 0;
           if (len === 0) {
               return -1;
           }
           var n = 0;
           if (arguments.length > 0) {
               n = Number(arguments[1]);
               if (n !== n) { // shortcut for verifying if it is NaN
                   n = 0;
               } else if (n !== 0 && n !== (1 / 0) && n !== -(1 / 0)) {
                   n = (n > 0 || -1) * Math.floor(Math.abs(n));
               }
           }
           if (n >= len) {
               return -1;
           }
           var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0);
           for (; k < len; k++) {
               if (k in t && t[k] === searchElement) {
                   return k;
               }
           }
           return -1;
       }
   }
   
   // ]]>
   </script>
   
   ENDJS
   
   }
   
 sub userbrowser_javascript {  sub userbrowser_javascript {
     my $id_functions = &javascript_index_functions();      my $id_functions = &javascript_index_functions();
     return <<"ENDUSERBRW";      return <<"ENDUSERBRW";
Line 766  sub selectcourse_link { Line 858  sub selectcourse_link {
    } elsif ($selecttype eq 'Course/Community') {     } elsif ($selecttype eq 'Course/Community') {
        $linktext = &mt('Select Course/Community');         $linktext = &mt('Select Course/Community');
        $type = '';         $type = '';
      } elsif ($selecttype eq 'Select') {
          $linktext = &mt('Select');
          $type = '';
    }     }
    return '<span class="LC_nobreak">'     return '<span class="LC_nobreak">'
          ."<a href='"           ."<a href='"
Line 795  sub check_uncheck_jscript { Line 890  sub check_uncheck_jscript {
 function checkAll(field) {  function checkAll(field) {
     if (field.length > 0) {      if (field.length > 0) {
         for (i = 0; i < field.length; i++) {          for (i = 0; i < field.length; i++) {
             field[i].checked = true ;              if (!field[i].disabled) { 
                   field[i].checked = true;
               }
         }          }
     } else {      } else {
         field.checked = true          if (!field.disabled) { 
               field.checked = true;
           }
     }      }
 }  }
     
Line 905  sub select_language { Line 1004  sub select_language {
   
 =pod  =pod
   
   
   =item * &list_languages()
   
   Returns an array reference that is suitable for use in language prompters.
   Each array element is itself a two element array.  The first element
   is the language code.  The second element a descsriptiuon of the 
   language itself.  This is suitable for use in e.g.
   &Apache::edit::select_arg (once dereferenced that is).
   
   =cut 
   
   sub list_languages {
       my @lang_choices;
   
       foreach my $id (&languageids()) {
    my $code = &supportedlanguagecode($id);
    if ($code) {
       my $selector    = $supported_codes{$id};
       my $description = &plainlanguagedescription($id);
       push (@lang_choices, [$selector, $description]);
    }
       }
       return \@lang_choices;
   }
   
   =pod
   
 =item * &linked_select_forms(...)  =item * &linked_select_forms(...)
   
 linked_select_forms returns a string containing a <script></script> block  linked_select_forms returns a string containing a <script></script> block
Line 1090  a new window using Javascript. (Default Line 1216  a new window using Javascript. (Default
   
 $width and $height are optional numerical parameters that will  $width and $height are optional numerical parameters that will
 override the width and height of the popped up window, which may  override the width and height of the popped up window, which may
 be useful for certain help topics with big pictures included.   be useful for certain help topics with big pictures included.
   
   $imgid is the id of the img tag used for the help icon. This may be
   used in a javascript call to switch the image src.  See 
   lonhtmlcommon::htmlareaselectactive() for an example.
   
 =cut  =cut
   
Line 1098  sub help_open_topic { Line 1228  sub help_open_topic {
     my ($topic, $text, $stayOnPage, $width, $height, $imgid) = @_;      my ($topic, $text, $stayOnPage, $width, $height, $imgid) = @_;
     $text = "" if (not defined $text);      $text = "" if (not defined $text);
     $stayOnPage = 0 if (not defined $stayOnPage);      $stayOnPage = 0 if (not defined $stayOnPage);
     $width = 350 if (not defined $width);      $width = 500 if (not defined $width);
     $height = 400 if (not defined $height);      $height = 400 if (not defined $height);
     my $filename = $topic;      my $filename = $topic;
     $filename =~ s/ /_/g;      $filename =~ s/ /_/g;
Line 1109  sub help_open_topic { Line 1239  sub help_open_topic {
     $topic=~s/\W/\_/g;      $topic=~s/\W/\_/g;
   
     if (!$stayOnPage) {      if (!$stayOnPage) {
  $link = "javascript:void(open('/adm/help/${filename}.hlp', 'Help_for_$topic', 'menubar=0,toolbar=1,scrollbars=1,width=$width,height=$height,resizable=yes'))";   $link = "javascript:openMyModal('/adm/help/${filename}.hlp',$width,$height,'yes');";
       } elsif ($stayOnPage eq 'popup') {
           $link = "javascript:void(open('/adm/help/${filename}.hlp', 'Help_for_$topic', 'menubar=0,toolbar=1,scrollbars=1,width=$width,height=$height,resizable=yes'))";
     } else {      } else {
  $link = "/adm/help/${filename}.hlp";   $link = "/adm/help/${filename}.hlp";
     }      }
Line 1130  sub help_open_topic { Line 1262  sub help_open_topic {
     $template.=' <a target="_top" href="'.$link.'" title="'.$title.'">'      $template.=' <a target="_top" href="'.$link.'" title="'.$title.'">'
               .'<img src="'.$helpicon.'" border="0"'                .'<img src="'.$helpicon.'" border="0"'
               .' alt="'.&mt('Help: [_1]',$topic).'"'                .' alt="'.&mt('Help: [_1]',$topic).'"'
               .' title="'.$title.'" style="vertical-align:middle;"'.$imgid                .' title="'.$title.'" style="vertical-align:middle;"'.$imgid 
               .' /></a>';                .' /></a>';
     if ($text ne "") {      if ($text ne "") {
         $template.='</span>';          $template.='</span>';
     }      }
     return $template;      return $template;
Line 1142  sub help_open_topic { Line 1274  sub help_open_topic {
 # This is a quicky function for Latex cheatsheet editing, since it   # This is a quicky function for Latex cheatsheet editing, since it 
 # appears in at least four places  # appears in at least four places
 sub helpLatexCheatsheet {  sub helpLatexCheatsheet {
     my ($topic,$text,$not_author) = @_;      my ($topic,$text,$not_author,$stayOnPage) = @_;
     my $out;      my $out;
     my $addOther = '';      my $addOther = '';
     if ($topic) {      if ($topic) {
  $addOther = '<span>'.&Apache::loncommon::help_open_topic($topic,&mt($text),   $addOther = '<span>'.&help_open_topic($topic,&mt($text),$stayOnPage, undef, 600).'</span> ';
        undef, undef, 600).  
    '</span> ';  
     }      }
     $out = '<span>' # Start cheatsheet      $out = '<span>' # Start cheatsheet
   .$addOther    .$addOther
           .'<span>'            .'<span>'
   .&Apache::loncommon::help_open_topic('Greek_Symbols',&mt('Greek Symbols'),    .&help_open_topic('Greek_Symbols',&mt('Greek Symbols'),$stayOnPage,undef,600)
        undef,undef,600)  
   .'</span> <span>'    .'</span> <span>'
   .&Apache::loncommon::help_open_topic('Other_Symbols',&mt('Other Symbols'),    .&help_open_topic('Other_Symbols',&mt('Other Symbols'),$stayOnPage,undef,600)
        undef,undef,600)  
   .'</span>';    .'</span>';
     unless ($not_author) {      unless ($not_author) {
         $out .= ' <span>'          $out .= ' <span>'
        .&Apache::loncommon::help_open_topic('Authoring_Output_Tags',&mt('Output Tags'),         .&help_open_topic('Authoring_Output_Tags',&mt('Output Tags'),$stayOnPage,undef,600)
                                             undef,undef,600)  
        .'</span>';         .'</span>';
     }      }
     $out .= '</span>'; # End cheatsheet      $out .= '</span>'; # End cheatsheet
Line 1205  ENDOUTPUT Line 1332  ENDOUTPUT
 sub help_open_menu {  sub help_open_menu {
     my ($topic,$component_help,$faq,$bug,$stayOnPage,$width,$height,$text)       my ($topic,$component_help,$faq,$bug,$stayOnPage,$width,$height,$text) 
  = @_;       = @_;    
     $stayOnPage = 0 if (not defined $stayOnPage);      $stayOnPage = 1;
     # only use pop-up help (stayOnPage == 0)  
     # if environment.remote is on (using remote control UI)  
     if ($env{'environment.remote'} eq 'off' ) {  
         $stayOnPage=1;  
     }  
     my $output;      my $output;
     if ($component_help) {      if ($component_help) {
  if (!$text) {   if (!$text) {
Line 1231  sub help_open_menu { Line 1353  sub help_open_menu {
 sub top_nav_help {  sub top_nav_help {
     my ($text) = @_;      my ($text) = @_;
     $text = &mt($text);      $text = &mt($text);
     my $stay_on_page =       my $stay_on_page = 1;
  ($env{'environment.remote'} eq 'off' );  
     my $link = ($stay_on_page) ? "javascript:helpMenu('display')"      my $link = ($stay_on_page) ? "javascript:helpMenu('display')"
                      : "javascript:helpMenu('open')";                       : "javascript:helpMenu('open')";
     my $banner_link = &update_help_link(undef,undef,undef,undef,$stay_on_page);      my $banner_link = &update_help_link(undef,undef,undef,undef,$stay_on_page);
Line 1247  END Line 1369  END
   
 sub help_menu_js {  sub help_menu_js {
     my ($text) = @_;      my ($text) = @_;
       my $stayOnPage = 1;
     my $stayOnPage =   
  ($env{'environment.remote'} eq 'off' );  
   
     my $width = 620;      my $width = 620;
     my $height = 600;      my $height = 600;
     my $helptopic=&general_help();      my $helptopic=&general_help();
Line 1291  function helpMenu(target) { Line 1410  function helpMenu(target) {
     return;      return;
 }  }
 function writeHelp(caller) {  function writeHelp(caller) {
     caller.document.writeln('$start_page<frame name="bannerframe"  src="'+banner_link+'" /><frame name="bodyframe" src="$details_link" /> $end_page')      caller.document.writeln('$start_page\\n<frame name="bannerframe" src="'+banner_link+'" />\\n<frame name="bodyframe" src="$details_link" />\\n$end_page')
     caller.document.close()      caller.document.close()
     caller.focus()      caller.focus()
 }  }
Line 1307  sub help_open_bug { Line 1426  sub help_open_bug {
     unless ($env{'user.adv'}) { return ''; }      unless ($env{'user.adv'}) { return ''; }
     unless ($Apache::lonnet::perlvar{'BugzillaHost'}) { return ''; }      unless ($Apache::lonnet::perlvar{'BugzillaHost'}) { return ''; }
     $text = "" if (not defined $text);      $text = "" if (not defined $text);
     $stayOnPage = 0 if (not defined $stayOnPage);  
     if ($env{'environment.remote'} eq 'off' ) {  
  $stayOnPage=1;   $stayOnPage=1;
     }  
     $width = 600 if (not defined $width);      $width = 600 if (not defined $width);
     $height = 600 if (not defined $height);      $height = 600 if (not defined $height);
   
Line 1351  sub help_open_faq { Line 1467  sub help_open_faq {
     unless ($env{'user.adv'}) { return ''; }      unless ($env{'user.adv'}) { return ''; }
     unless ($Apache::lonnet::perlvar{'FAQHost'}) { return ''; }      unless ($Apache::lonnet::perlvar{'FAQHost'}) { return ''; }
     $text = "" if (not defined $text);      $text = "" if (not defined $text);
     $stayOnPage = 0 if (not defined $stayOnPage);  
     if ($env{'environment.remote'} eq 'off' ) {  
  $stayOnPage=1;   $stayOnPage=1;
     }  
     $width = 350 if (not defined $width);      $width = 350 if (not defined $width);
     $height = 400 if (not defined $height);      $height = 400 if (not defined $height);
   
Line 1671  Inputs: $workbook Line 1784  Inputs: $workbook
   
 Returns: $format, a hash reference.  Returns: $format, a hash reference.
   
   
 =cut  =cut
   
 ###############################################################  ###############################################################
Line 1732  sub create_workbook { Line 1846  sub create_workbook {
         return (undef);          return (undef);
     }      }
     #      #
     $workbook->set_tempdir('/home/httpd/perl/tmp');      $workbook->set_tempdir(LONCAPA::tempdir());
     #      #
     my $format = &Apache::loncommon::define_excel_formats($workbook);      my $format = &Apache::loncommon::define_excel_formats($workbook);
     return ($workbook,$filename,$format);      return ($workbook,$filename,$format);
Line 1870  sub multiple_select_form { Line 1984  sub multiple_select_form {
 Returns a string containing a <select name='$name' size='1'> form to   Returns a string containing a <select name='$name' size='1'> form to 
 allow a user to select options from a ref to a hash containing:  allow a user to select options from a ref to a hash containing:
 option_name => displayed text. An optional $onchange can include  option_name => displayed text. An optional $onchange can include
 a javascript onchange item, e.g., onchange="this.form.submit();"  a javascript onchange item, e.g., onchange="this.form.submit();"  
   
 See lonrights.pm for an example invocation and use.  See lonrights.pm for an example invocation and use.
   
Line 1886  sub select_form { Line 2000  sub select_form {
     my $selectform = "<select name=\"$name\" size=\"1\"$onchange>\n";      my $selectform = "<select name=\"$name\" size=\"1\"$onchange>\n";
     my @keys;      my @keys;
     if (exists($hashref->{'select_form_order'})) {      if (exists($hashref->{'select_form_order'})) {
         @keys=@{$hashref->{'select_form_order'}};   @keys=@{$hashref->{'select_form_order'}};
     } else {      } else {
         @keys=sort(keys(%{$hashref}));   @keys=sort(keys(%{$hashref}));
     }      }
     foreach my $key (@keys) {      foreach my $key (@keys) {
         $selectform.=          $selectform.=
Line 1903  sub select_form { Line 2017  sub select_form {
 # For display filters  # For display filters
   
 sub display_filter {  sub display_filter {
       my ($context) = @_;
     if (!$env{'form.show'}) { $env{'form.show'}=10; }      if (!$env{'form.show'}) { $env{'form.show'}=10; }
     if (!$env{'form.displayfilter'}) { $env{'form.displayfilter'}='currentfolder'; }      if (!$env{'form.displayfilter'}) { $env{'form.displayfilter'}='currentfolder'; }
     return '<span class="LC_nobreak"><label>'.&mt('Records [_1]',      my $phraseinput = 'hidden';
       my $includeinput = 'hidden';
       my ($checked,$includetypestext);
       if ($env{'form.displayfilter'} eq 'containing') {
           $phraseinput = 'text'; 
           if ($context eq 'parmslog') {
               $includeinput = 'checkbox';
               if ($env{'form.includetypes'}) {
                   $checked = ' checked="checked"';
               }
               $includetypestext = &mt('Include parameter types');
           }
       } else {
           $includetypestext = '&nbsp;';
       }
       my ($additional,$secondid,$thirdid);
       if ($context eq 'parmslog') {
           $additional = 
               '<label><input type="'.$includeinput.'" name="includetypes"'. 
               $checked.' name="includetypes" value="1" id="includetypes" />'.
               '&nbsp;<span id="includetypestext">'.$includetypestext.'</span>'.
               '</label>';
           $secondid = 'includetypes';
           $thirdid = 'includetypestext';
       }
       my $onchange = "javascript:toggleHistoryOptions(this,'containingphrase','$context',
                                                       '$secondid','$thirdid')";
       return '<span class="LC_nobreak"><label>'.&mt('Records: [_1]',
        &Apache::lonmeta::selectbox('show',$env{'form.show'},undef,         &Apache::lonmeta::selectbox('show',$env{'form.show'},undef,
    (&mt('all'),10,20,50,100,1000,10000))).     (&mt('all'),10,20,50,100,1000,10000))).
    '</label></span> <span class="LC_nobreak">'.     '</label></span> <span class="LC_nobreak">'.
            &mt('Filter [_1]',             &mt('Filter: [_1]',
    &select_form($env{'form.displayfilter'},     &select_form($env{'form.displayfilter'},
  'displayfilter',   'displayfilter',
  {'currentfolder' => 'Current folder/page',   {'currentfolder' => 'Current folder/page',
  'containing' => 'Containing phrase',   'containing' => 'Containing phrase',
  'none' => 'None'})).   'none' => 'None'},$onchange)).'&nbsp;'.
  '<input type="text" name="containingphrase" size="30" value="'.&HTML::Entities::encode($env{'form.containingphrase'}).'" /></span>';   '<input type="'.$phraseinput.'" name="containingphrase" id="containingphrase" size="30" value="'.
                            &HTML::Entities::encode($env{'form.containingphrase'}).
                            '" />'.$additional;
   }
   
   sub display_filter_js {
       my $includetext = &mt('Include parameter types');
       return <<"ENDJS";
     
   function toggleHistoryOptions(setter,firstid,context,secondid,thirdid) {
       var firstType = 'hidden';
       if (setter.options[setter.selectedIndex].value == 'containing') {
           firstType = 'text';
       }
       firstObject = document.getElementById(firstid);
       if (typeof(firstObject) == 'object') {
           if (firstObject.type != firstType) {
               changeInputType(firstObject,firstType);
           }
       }
       if (context == 'parmslog') {
           var secondType = 'hidden';
           if (firstType == 'text') {
               secondType = 'checkbox';
           }
           secondObject = document.getElementById(secondid);  
           if (typeof(secondObject) == 'object') {
               if (secondObject.type != secondType) {
                   changeInputType(secondObject,secondType);
               }
           }
           var textItem = document.getElementById(thirdid);
           var currtext = textItem.innerHTML;
           var newtext;
           if (firstType == 'text') {
               newtext = '$includetext';
           } else {
               newtext = '&nbsp;';
           }
           if (currtext != newtext) {
               textItem.innerHTML = newtext;
           }
       }
       return;
   }
   
   function changeInputType(oldObject,newType) {
       var newObject = document.createElement('input');
       newObject.type = newType;
       if (oldObject.size) {
           newObject.size = oldObject.size;
       }
       if (oldObject.value) {
           newObject.value = oldObject.value;
       }
       if (oldObject.name) {
           newObject.name = oldObject.name;
       }
       if (oldObject.id) {
           newObject.id = oldObject.id;
       }
       oldObject.parentNode.replaceChild(newObject,oldObject);
       return;
   }
   
   ENDJS
 }  }
   
 sub gradeleveldescription {  sub gradeleveldescription {
Line 2287  function set_auth_radio_buttons(newvalue Line 2494  function set_auth_radio_buttons(newvalue
     var numauthchoices = currentform.login.length;      var numauthchoices = currentform.login.length;
     if (typeof numauthchoices  == "undefined") {      if (typeof numauthchoices  == "undefined") {
         return;          return;
     }      } 
     var i=0;      var i=0;
     while (i < numauthchoices) {      while (i < numauthchoices) {
         if (currentform.login[i].value == newvalue) { break; }          if (currentform.login[i].value == newvalue) { break; }
Line 2304  END Line 2511  END
     return $result;      return $result;
 }  }
   
 sub authform_authorwarning{  sub authform_authorwarning {
     my $result='';      my $result='';
     $result='<i>'.      $result='<i>'.
         &mt('As a general rule, only authors or co-authors should be '.          &mt('As a general rule, only authors or co-authors should be '.
Line 2313  sub authform_authorwarning{ Line 2520  sub authform_authorwarning{
     return $result;      return $result;
 }  }
   
 sub authform_nochange{    sub authform_nochange {
     my %in = (      my %in = (
               formname => 'document.cu',                formname => 'document.cu',
               kerb_def_dom => 'MSU.EDU',                kerb_def_dom => 'MSU.EDU',
               @_,                @_,
           );            );
     my ($authnum,%can_assign) =  &get_assignable_auth($in{'domain'});       my ($authnum,%can_assign) = &get_assignable_auth($in{'domain'});
     my $result;      my $result;
     if (keys(%can_assign) == 0) {      if (!$authnum) {
         $result = &mt('Under you current role you are not permitted to change login settings for this user');            $result = &mt('Under your current role you are not permitted to change login settings for this user');
     } else {      } else {
         $result = '<label>'.&mt('[_1] Do not change login data',          $result = '<label>'.&mt('[_1] Do not change login data',
                   '<input type="radio" name="login" value="nochange" '.                    '<input type="radio" name="login" value="nochange" '.
Line 2342  sub authform_kerberos { Line 2549  sub authform_kerberos {
               );                );
     my ($check4,$check5,$krbcheck,$krbarg,$krbver,$result,$authtype,      my ($check4,$check5,$krbcheck,$krbarg,$krbver,$result,$authtype,
         $autharg,$jscall);          $autharg,$jscall);
     my ($authnum,%can_assign) =  &get_assignable_auth($in{'domain'});      my ($authnum,%can_assign) = &get_assignable_auth($in{'domain'});
     if ($in{'kerb_def_auth'} eq 'krb5') {      if ($in{'kerb_def_auth'} eq 'krb5') {
        $check5 = ' checked="checked"';         $check5 = ' checked="checked"';
     } else {      } else {
Line 2392  sub authform_kerberos { Line 2599  sub authform_kerberos {
         if (defined($in{'mode'})) {          if (defined($in{'mode'})) {
             if ($in{'mode'} eq 'modifycourse') {              if ($in{'mode'} eq 'modifycourse') {
                 if ($authnum == 1) {                  if ($authnum == 1) {
                     $authtype = '<input type="hidden" name="login" value="krb" />';                      $authtype = '<input type="radio" name="login" value="krb" />';
                 }                  }
             }              }
         }          }
Line 2404  sub authform_kerberos { Line 2611  sub authform_kerberos {
                     $krbcheck.' />';                      $krbcheck.' />';
     }      }
     if (($can_assign{'krb4'} && $can_assign{'krb5'}) ||      if (($can_assign{'krb4'} && $can_assign{'krb5'}) ||
         ($can_assign{'krb4'} && !$can_assign{'krb5'} &&           ($can_assign{'krb4'} && !$can_assign{'krb5'} &&
          $in{'curr_authtype'} eq 'krb5') ||           $in{'curr_authtype'} eq 'krb5') ||
         (!$can_assign{'krb4'} && $can_assign{'krb5'} &&           (!$can_assign{'krb4'} && $can_assign{'krb5'} &&
          $in{'curr_authtype'} eq 'krb4')) {           $in{'curr_authtype'} eq 'krb4')) {
         $result .= &mt          $result .= &mt
         ('[_1] Kerberos authenticated with domain [_2] '.          ('[_1] Kerberos authenticated with domain [_2] '.
Line 2442  sub authform_kerberos { Line 2649  sub authform_kerberos {
     return $result;      return $result;
 }  }
   
 sub authform_internal{    sub authform_internal {
     my %in = (      my %in = (
                 formname => 'document.cu',                  formname => 'document.cu',
                 kerb_def_dom => 'MSU.EDU',                  kerb_def_dom => 'MSU.EDU',
                 @_,                  @_,
                 );                  );
     my ($intcheck,$intarg,$result,$authtype,$autharg,$jscall);      my ($intcheck,$intarg,$result,$authtype,$autharg,$jscall);
     my ($authnum,%can_assign) =  &get_assignable_auth($in{'domain'});      my ($authnum,%can_assign) = &get_assignable_auth($in{'domain'});
     if (defined($in{'curr_authtype'})) {      if (defined($in{'curr_authtype'})) {
         if ($in{'curr_authtype'} eq 'int') {          if ($in{'curr_authtype'} eq 'int') {
             if ($can_assign{'int'}) {              if ($can_assign{'int'}) {
Line 2478  sub authform_internal{ Line 2685  sub authform_internal{
         if (defined($in{'mode'})) {          if (defined($in{'mode'})) {
             if ($in{'mode'} eq 'modifycourse') {              if ($in{'mode'} eq 'modifycourse') {
                 if ($authnum == 1) {                  if ($authnum == 1) {
                     $authtype = '<input type="hidden" name="login" value="int" />';                      $authtype = '<input type="radio" name="login" value="int" />';
                 }                  }
             }              }
         }          }
Line 2497  sub authform_internal{ Line 2704  sub authform_internal{
     return $result;      return $result;
 }  }
   
 sub authform_local{    sub authform_local {
     my %in = (      my %in = (
               formname => 'document.cu',                formname => 'document.cu',
               kerb_def_dom => 'MSU.EDU',                kerb_def_dom => 'MSU.EDU',
               @_,                @_,
               );                );
     my ($loccheck,$locarg,$result,$authtype,$autharg,$jscall);      my ($loccheck,$locarg,$result,$authtype,$autharg,$jscall);
     my ($authnum,%can_assign) =  &get_assignable_auth($in{'domain'});      my ($authnum,%can_assign) = &get_assignable_auth($in{'domain'});
     if (defined($in{'curr_authtype'})) {      if (defined($in{'curr_authtype'})) {
         if ($in{'curr_authtype'} eq 'loc') {          if ($in{'curr_authtype'} eq 'loc') {
             if ($can_assign{'loc'}) {              if ($can_assign{'loc'}) {
Line 2533  sub authform_local{ Line 2740  sub authform_local{
         if (defined($in{'mode'})) {          if (defined($in{'mode'})) {
             if ($in{'mode'} eq 'modifycourse') {              if ($in{'mode'} eq 'modifycourse') {
                 if ($authnum == 1) {                  if ($authnum == 1) {
                     $authtype = '<input type="hidden" name="login" value="loc" />';                      $authtype = '<input type="radio" name="login" value="loc" />';
                 }                  }
             }              }
         }          }
Line 2551  sub authform_local{ Line 2758  sub authform_local{
     return $result;      return $result;
 }  }
   
 sub authform_filesystem{    sub authform_filesystem {
     my %in = (      my %in = (
               formname => 'document.cu',                formname => 'document.cu',
               kerb_def_dom => 'MSU.EDU',                kerb_def_dom => 'MSU.EDU',
               @_,                @_,
               );                );
     my ($fsyscheck,$result,$authtype,$autharg,$jscall);      my ($fsyscheck,$result,$authtype,$autharg,$jscall);
     my ($authnum,%can_assign) =  &get_assignable_auth($in{'domain'});      my ($authnum,%can_assign) = &get_assignable_auth($in{'domain'});
     if (defined($in{'curr_authtype'})) {      if (defined($in{'curr_authtype'})) {
         if ($in{'curr_authtype'} eq 'fsys') {          if ($in{'curr_authtype'} eq 'fsys') {
             if ($can_assign{'fsys'}) {              if ($can_assign{'fsys'}) {
Line 2584  sub authform_filesystem{ Line 2791  sub authform_filesystem{
         if (defined($in{'mode'})) {          if (defined($in{'mode'})) {
             if ($in{'mode'} eq 'modifycourse') {              if ($in{'mode'} eq 'modifycourse') {
                 if ($authnum == 1) {                  if ($authnum == 1) {
                     $authtype = '<input type="hidden" name="login" value="fsys" />';                      $authtype = '<input type="radio" name="login" value="fsys" />';
                 }                  }
             }              }
         }          }
Line 2779  database which holds them. Line 2986  database which holds them.
   
 Uses global $thesaurus_db_file.  Uses global $thesaurus_db_file.
   
   
 =cut  =cut
   
 ###############################################################  ###############################################################
Line 2814  sub get_related_words { Line 3022  sub get_related_words {
     untie %thesaurus_db;      untie %thesaurus_db;
     return @Words;      return @Words;
 }  }
   ###############################################################
   #
   #  Spell checking
   #
   
   =pod
   
   =head1 Spell checking
   
   =over 4
   
   =item * &check_spelling($wordlist $language)
   
   Takes a string containing words and feeds it to an external
   spellcheck program via a pipeline. Returns a string containing
   them mis-spelled words.
   
   Parameters:
   
   =over 4
   
   =item - $wordlist
   
   String that will be fed into the spellcheck program.
   
   =item - $language
   
   Language string that specifies the language for which the spell
   check will be performed.
   
   =back
   
   =back
   
   Note: This sub assumes that aspell is installed.
   
   
   =cut
   
   
 =pod  =pod
   
Line 2821  sub get_related_words { Line 3068  sub get_related_words {
   
 =cut  =cut
   
   sub check_spelling {
       my ($wordlist, $language) = @_;
       my @misspellings;
       
       # Generate the speller and set the langauge.
       # if explicitly selected:
   
       my $speller = Text::Aspell->new;
       if ($language) {
    $speller->set_option('lang', $language);
       }
   
       # Turn the word list into an array of words by splittingon whitespace
   
       my @words = split(/\s+/, $wordlist);
   
       foreach my $word (@words) {
    if(! $speller->check($word)) {
       push(@misspellings, $word);
    }
       }
       return join(' ', @misspellings);
       
   }
   
 # -------------------------------------------------------------- Plaintext name  # -------------------------------------------------------------- Plaintext name
 =pod  =pod
   
Line 3050  sub noteswrapper { Line 3322  sub noteswrapper {
 # ------------------------------------------------------------- Aboutme Wrapper  # ------------------------------------------------------------- Aboutme Wrapper
   
 sub aboutmewrapper {  sub aboutmewrapper {
     my ($link,$username,$domain,$target)=@_;      my ($link,$username,$domain,$target,$class)=@_;
     if (!defined($username)  && !defined($domain)) {      if (!defined($username)  && !defined($domain)) {
         return;          return;
     }      }
     return '<a href="/adm/'.$domain.'/'.$username.'/aboutme?forcestudent=1"'.      return '<a href="/adm/'.$domain.'/'.$username.'/aboutme"'.
  ($target?' target="$target"':'').' title="'.&mt("View this user's personal information page").'">'.$link.'</a>';   ($target?' target="'.$target.'"':'').($class?' class="'.$class.'"':'').' title="'.&mt("View this user's personal information page").'">'.$link.'</a>';
 }  }
   
 # ------------------------------------------------------------ Syllabus Wrapper  # ------------------------------------------------------------ Syllabus Wrapper
Line 3156  sub languagedescription { Line 3428  sub languagedescription {
     ($supported_language{$code}?' ('.&mt('interface available').')':'');      ($supported_language{$code}?' ('.&mt('interface available').')':'');
 }  }
   
   =pod
   
   =item * &plainlanguagedescription
   
   Returns both the plain language description (e.g. 'Creoles and Pidgins, English-based (Other)')
   and the language character encoding (e.g. ISO) separated by a ' - ' string.
   
   =cut
   
 sub plainlanguagedescription {  sub plainlanguagedescription {
     my $code=shift;      my $code=shift;
     return $language{$code};      return $language{$code};
 }  }
   
   =pod
   
   =item * &supportedlanguagecode
   
   Returns the supported language code (e.g. sptutf maps to pt) given a language
   code.
   
   =cut
   
 sub supportedlanguagecode {  sub supportedlanguagecode {
     my $code=shift;      my $code=shift;
     return $supported_language{$code};      return $supported_language{$code};
Line 3168  sub supportedlanguagecode { Line 3458  sub supportedlanguagecode {
   
 =pod  =pod
   
   =item * &latexlanguage()
   
   Given a language key code returns the correspondnig language to use
   to select the correct hyphenation on LaTeX printouts.  This is undef if there
   is no supported hyphenation for the language code.
   
   =cut
   
   sub latexlanguage {
       my $code = shift;
       return $latex_language{$code};
   }
   
   =pod
   
   =item * &latexhyphenation()
   
   Same as above but what's supplied is the language as it might be stored
   in the metadata.
   
   =cut
   
   sub latexhyphenation {
       my $key = shift;
       return $latex_language_bykey{$key};
   }
   
   =pod
   
 =item * &copyrightids()   =item * &copyrightids() 
   
 returns list of all copyrights  returns list of all copyrights
Line 3260  sub filemimetype { Line 3579  sub filemimetype {
 sub filecategoryselect {  sub filecategoryselect {
     my ($name,$value)=@_;      my ($name,$value)=@_;
     return &select_form($value,$name,      return &select_form($value,$name,
  {'' => &mt('Any category'), map { $_,$_ } sort(keys(%category_extensions))});                          {'' => &mt('Any category'), map { $_,$_ } sort(keys(%category_extensions))});
 }  }
   
 =pod  =pod
Line 3433  sub get_previous_attempt { Line 3752  sub get_previous_attempt {
   my $data=$parts[-1];    my $data=$parts[-1];
           next if ($data eq 'foilorder');            next if ($data eq 'foilorder');
   pop(@parts);    pop(@parts);
             $prevattempts.='<th>'.&mt('Part ').join('.',@parts).'<br />'.$data.'&nbsp;</th>';
           if ($data eq 'type') {            if ($data eq 'type') {
               unless ($showsurv) {                unless ($showsurv) {
                   my $id = join(',',@parts);                    my $id = join(',',@parts);
Line 3441  sub get_previous_attempt { Line 3761  sub get_previous_attempt {
                       $lasthidden{$ign.'.'.$id} = 1;                        $lasthidden{$ign.'.'.$id} = 1;
                   }                    }
               }                }
               delete($lasthash{$key});            } 
           } else {  
       $prevattempts.='<th>'.&mt('Part ').join('.',@parts).'<br />'.$data.'&nbsp;</th>';  
           }  
  } else {   } else {
   if ($#parts == 0) {    if ($#parts == 0) {
     $prevattempts.='<th>'.$parts[0].'</th>';      $prevattempts.='<th>'.$parts[0].'</th>';
Line 3561  sub get_previous_attempt { Line 3878  sub get_previous_attempt {
   
 sub format_previous_attempt_value {  sub format_previous_attempt_value {
     my ($key,$value) = @_;      my ($key,$value) = @_;
     if ($key =~ /timestamp/) {      if (($key =~ /timestamp/) || ($key=~/duedate/)) {
  $value = &Apache::lonlocal::locallocaltime($value);   $value = &Apache::lonlocal::locallocaltime($value);
     } elsif (ref($value) eq 'ARRAY') {      } elsif (ref($value) eq 'ARRAY') {
  $value = '('.join(', ', @{ $value }).')';   $value = '('.join(', ', @{ $value }).')';
Line 3575  sub format_previous_attempt_value { Line 3892  sub format_previous_attempt_value {
             }              }
             my $tag_internal_answer_name = 'INTERNAL';              my $tag_internal_answer_name = 'INTERNAL';
             if ($anskeys[0] eq $tag_internal_answer_name) {              if ($anskeys[0] eq $tag_internal_answer_name) {
                 $value = $answer;                  $value = $answer; 
             } else {              } else {
                 $value = $anskeys[0].'='.$answer;                  $value = $anskeys[0].'='.$answer;
             }              }
Line 3586  sub format_previous_attempt_value { Line 3903  sub format_previous_attempt_value {
                     $answer =~ s{\0}{,}g;                      $answer =~ s{\0}{,}g;
                 }                  }
                 $value .=  $ans.'='.$answer.'<br />';;                  $value .=  $ans.'='.$answer.'<br />';;
             }              } 
         }          }
     } else {      } else {
  $value = &unescape($value);   $value = &unescape($value);
Line 3866  sub findallcourses { Line 4183  sub findallcourses {
         $udom = $env{'user.domain'};          $udom = $env{'user.domain'};
     }      }
     if (($uname ne $env{'user.name'}) || ($udom ne $env{'user.domain'})) {      if (($uname ne $env{'user.name'}) || ($udom ne $env{'user.domain'})) {
         my $extra = &Apache::lonnet::freeze_escape({'skipcheck' => 1});          my %roleshash = &Apache::lonnet::dump('roles',$udom,$uname);
         my %roleshash = &Apache::lonnet::dump('roles',$udom,$uname,'.',undef,  
                                               $extra);  
         if (!%roles) {          if (!%roles) {
             %roles = (              %roles = (
                        cc => 1,                         cc => 1,
Line 3893  sub findallcourses { Line 4208  sub findallcourses {
             if ($tstart) {              if ($tstart) {
                 next if ($tstart > $now);                  next if ($tstart > $now);
             }              }
             my ($cdom,$cnum,$sec,$cnumpart,$secpart,$role,$realsec);              my ($cdom,$cnum,$sec,$cnumpart,$secpart,$role);
             (undef,$cdom,$cnumpart,$secpart) = split(/\//,$entry);              (undef,$cdom,$cnumpart,$secpart) = split(/\//,$entry);
               my $value = $trole.'/'.$cdom.'/';
             if ($secpart eq '') {              if ($secpart eq '') {
                 ($cnum,$role) = split(/_/,$cnumpart);                   ($cnum,$role) = split(/_/,$cnumpart); 
                 $sec = 'none';                  $sec = 'none';
                 $realsec = '';                  $value .= $cnum.'/';
             } else {              } else {
                 $cnum = $cnumpart;                  $cnum = $cnumpart;
                 ($sec,$role) = split(/_/,$secpart);                  ($sec,$role) = split(/_/,$secpart);
                 $realsec = $sec;                  $value .= $cnum.'/'.$sec;
               }
               if (ref($courses{$cdom.'_'.$cnum}{$sec}) eq 'ARRAY') {
                   unless (grep(/^\Q$value\E$/,@{$courses{$cdom.'_'.$cnum}{$sec}})) {
                       push(@{$courses{$cdom.'_'.$cnum}{$sec}},$value);
                   }
               } else {
                   @{$courses{$cdom.'_'.$cnum}{$sec}} = ($value);
             }              }
             $courses{$cdom.'_'.$cnum}{$sec} = $trole.'/'.$cdom.'/'.$cnum.'/'.$realsec;  
         }          }
     } else {      } else {
         foreach my $key (keys(%env)) {          foreach my $key (keys(%env)) {
Line 3922  sub findallcourses { Line 4244  sub findallcourses {
                     if ($now>$endtime) { $active=0; }                      if ($now>$endtime) { $active=0; }
                 }                  }
                 if ($active) {                  if ($active) {
                       my $value = $role.'/'.$cdom.'/'.$cnum.'/';
                     if ($sec eq '') {                      if ($sec eq '') {
                         $sec = 'none';                          $sec = 'none';
                       } else {
                           $value .= $sec;
                       }
                       if (ref($courses{$cdom.'_'.$cnum}{$sec}) eq 'ARRAY') {
                           unless (grep(/^\Q$value\E$/,@{$courses{$cdom.'_'.$cnum}{$sec}})) {
                               push(@{$courses{$cdom.'_'.$cnum}{$sec}},$value);
                           }
                       } else {
                           @{$courses{$cdom.'_'.$cnum}{$sec}} = ($value);
                     }                      }
                     $courses{$cdom.'_'.$cnum}{$sec} =   
                                      $role.'/'.$cdom.'/'.$cnum.'/'.$sec;  
                 }                  }
             }              }
         }          }
Line 3937  sub findallcourses { Line 4267  sub findallcourses {
 ###############################################  ###############################################
   
 sub blockcheck {  sub blockcheck {
     my ($setters,$activity,$uname,$udom) = @_;      my ($setters,$activity,$uname,$udom,$url) = @_;
   
     if (!defined($udom)) {      if (!defined($udom)) {
         $udom = $env{'user.domain'};          $udom = $env{'user.domain'};
Line 3949  sub blockcheck { Line 4279  sub blockcheck {
     # If uname and udom are for a course, check for blocks in the course.      # If uname and udom are for a course, check for blocks in the course.
   
     if (&Apache::lonnet::is_course($udom,$uname)) {      if (&Apache::lonnet::is_course($udom,$uname)) {
         my %records = &Apache::lonnet::dump('comm_block',$udom,$uname);          my ($startblock,$endblock,$triggerblock) = 
         my ($startblock,$endblock)=&get_blocks($setters,$activity,$udom,$uname);              &get_blocks($setters,$activity,$udom,$uname,$url);
         return ($startblock,$endblock);          return ($startblock,$endblock,$triggerblock);
     }      }
   
     my $startblock = 0;      my $startblock = 0;
     my $endblock = 0;      my $endblock = 0;
       my $triggerblock = '';
     my %live_courses = &findallcourses(undef,$uname,$udom);      my %live_courses = &findallcourses(undef,$uname,$udom);
   
     # If uname is for a user, and activity is course-specific, i.e.,      # If uname is for a user, and activity is course-specific, i.e.,
Line 4019  sub blockcheck { Line 4350  sub blockcheck {
             if ($otheruser) {              if ($otheruser) {
                 # Resource belongs to user other than current user.                  # Resource belongs to user other than current user.
                 # Assemble privs for that user, and check for 'evb' priv.                  # Assemble privs for that user, and check for 'evb' priv.
                 my ($trole,$tdom,$tnum,$tsec);                  my (%allroles,%userroles);
                 my $entry = $live_courses{$course}{$sec};                  if (ref($live_courses{$course}{$sec}) eq 'ARRAY') {
                 if ($entry =~ /^cr/) {                      foreach my $entry (@{$live_courses{$course}{$sec}}) { 
                     ($trole,$tdom,$tnum,$tsec) =                           my ($trole,$tdom,$tnum,$tsec);
                       ($entry =~ m|^(cr/$match_domain/$match_username/\w+)\./($match_domain)/($match_username)/?(\w*)$|);                          if ($entry =~ /^cr/) {
                 } else {                              ($trole,$tdom,$tnum,$tsec) = 
                     ($trole,$tdom,$tnum,$tsec) = split(/\//,$entry);                                  ($entry =~ m|^(cr/$match_domain/$match_username/\w+)\./($match_domain)/($match_username)/?(\w*)$|);
                 }                          } else {
                 my ($spec,$area,$trest,%allroles,%userroles);                             ($trole,$tdom,$tnum,$tsec) = split(/\//,$entry);
                 $area = '/'.$tdom.'/'.$tnum;                          }
                 $trest = $tnum;                          my ($spec,$area,$trest);
                 if ($tsec ne '') {                          $area = '/'.$tdom.'/'.$tnum;
                     $area .= '/'.$tsec;                          $trest = $tnum;
                     $trest .= '/'.$tsec;                          if ($tsec ne '') {
                 }                              $area .= '/'.$tsec;
                 $spec = $trole.'.'.$area;                              $trest .= '/'.$tsec;
                 if ($trole =~ /^cr/) {                          }
                     &Apache::lonnet::custom_roleprivs(\%allroles,$trole,                          $spec = $trole.'.'.$area;
                                                       $tdom,$spec,$trest,$area);                          if ($trole =~ /^cr/) {
                 } else {                              &Apache::lonnet::custom_roleprivs(\%allroles,$trole,
                     &Apache::lonnet::standard_roleprivs(\%allroles,$trole,                                                                $tdom,$spec,$trest,$area);
                                                        $tdom,$spec,$trest,$area);                          } else {
                 }                              &Apache::lonnet::standard_roleprivs(\%allroles,$trole,
                 my ($author,$adv) = &Apache::lonnet::set_userprivs(\%userroles,\%allroles);                                                                  $tdom,$spec,$trest,$area);
                 if ($userroles{'user.priv.'.$checkrole} =~ /evb\&([^\:]*)/) {                          }
                     if ($1) {                      }
                         $no_userblock = 1;                      my ($author,$adv) = &Apache::lonnet::set_userprivs(\%userroles,\%allroles);
                         last;                      if ($userroles{'user.priv.'.$checkrole} =~ /evb\&([^\:]*)/) {
                           if ($1) {
                               $no_userblock = 1;
                               last;
                           }
                     }                      }
                 }                  }
             } else {              } else {
Line 4066  sub blockcheck { Line 4401  sub blockcheck {
         # Retrieve blocking times and identity of locker for course          # Retrieve blocking times and identity of locker for course
         # of specified user, unless user has 'evb' privilege.          # of specified user, unless user has 'evb' privilege.
                   
         my ($start,$end)=&get_blocks($setters,$activity,$cdom,$cnum);          my ($start,$end,$trigger) = 
               &get_blocks($setters,$activity,$cdom,$cnum,$url);
         if (($start != 0) &&           if (($start != 0) && 
             (($startblock == 0) || ($startblock > $start))) {              (($startblock == 0) || ($startblock > $start))) {
             $startblock = $start;              $startblock = $start;
               if ($trigger ne '') {
                   $triggerblock = $trigger;
               }
         }          }
         if (($end != 0)  &&          if (($end != 0)  &&
             (($endblock == 0) || ($endblock < $end))) {              (($endblock == 0) || ($endblock < $end))) {
             $endblock = $end;              $endblock = $end;
               if ($trigger ne '') {
                   $triggerblock = $trigger;
               }
         }          }
     }      }
     return ($startblock,$endblock);      return ($startblock,$endblock,$triggerblock);
 }  }
   
 sub get_blocks {  sub get_blocks {
     my ($setters,$activity,$cdom,$cnum) = @_;      my ($setters,$activity,$cdom,$cnum,$url) = @_;
     my $startblock = 0;      my $startblock = 0;
     my $endblock = 0;      my $endblock = 0;
       my $triggerblock = '';
     my $course = $cdom.'_'.$cnum;      my $course = $cdom.'_'.$cnum;
     $setters->{$course} = {};      $setters->{$course} = {};
     $setters->{$course}{'staff'} = [];      $setters->{$course}{'staff'} = [];
     $setters->{$course}{'times'} = [];      $setters->{$course}{'times'} = [];
     my %records = &Apache::lonnet::dump('comm_block',$cdom,$cnum);      $setters->{$course}{'triggers'} = [];
     foreach my $record (keys(%records)) {      my (@blockers,%triggered);
         my ($start,$end) = ($record =~ m/^(\d+)____(\d+)$/);      my $now = time;
         if ($start <= time && $end >= time) {      my %commblocks = &Apache::lonnet::get_comm_blocks($cdom,$cnum);
             my ($staff_name,$staff_dom,$title,$blocks) =      if ($activity eq 'docs') {
                 &parse_block_record($records{$record});          @blockers = &Apache::lonnet::has_comm_blocking('bre',undef,$url,\%commblocks);
             if ($blocks->{$activity} eq 'on') {          foreach my $block (@blockers) {
                 push(@{$$setters{$course}{'staff'}},[$staff_name,$staff_dom]);              if ($block =~ /^firstaccess____(.+)$/) {
                 push(@{$$setters{$course}{'times'}}, [$start,$end]);                  my $item = $1;
                 if ( ($startblock == 0) || ($startblock > $start) ) {                  my $type = 'map';
                     $startblock = $start;                  my $timersymb = $item;
                   if ($item eq 'course') {
                       $type = 'course';
                   } elsif ($item =~ /___\d+___/) {
                       $type = 'resource';
                   } else {
                       $timersymb = &Apache::lonnet::symbread($item);
                 }                  }
                 if ( ($endblock == 0) || ($endblock < $end) ) {                  my $start = $env{'course.'.$cdom.'_'.$cnum.'.firstaccess.'.$timersymb};
                     $endblock = $end;                  my $end = $start + $env{'course.'.$cdom.'_'.$cnum.'.timerinterval.'.$timersymb};
                   $triggered{$block} = {
                                          start => $start,
                                          end   => $end,
                                          type  => $type,
                                        };
               }
           }
       } else {
           foreach my $block (keys(%commblocks)) {
               if ($block =~ m/^(\d+)____(\d+)$/) { 
                   my ($start,$end) = ($1,$2);
                   if ($start <= time && $end >= time) {
                       if (ref($commblocks{$block}) eq 'HASH') {
                           if (ref($commblocks{$block}{'blocks'}) eq 'HASH') {
                               if ($commblocks{$block}{'blocks'}{$activity} eq 'on') {
                                   unless(grep(/^\Q$block\E$/,@blockers)) {
                                       push(@blockers,$block);
                                   }
                               }
                           }
                       }
                 }                  }
               } elsif ($block =~ /^firstaccess____(.+)$/) {
                   my $item = $1;
                   my $timersymb = $item; 
                   my $type = 'map';
                   if ($item eq 'course') {
                       $type = 'course';
                   } elsif ($item =~ /___\d+___/) {
                       $type = 'resource';
                   } else {
                       $timersymb = &Apache::lonnet::symbread($item);
                   }
                   my $start = $env{'course.'.$cdom.'_'.$cnum.'.firstaccess.'.$timersymb};
                   my $end = $start + $env{'course.'.$cdom.'_'.$cnum.'.timerinterval.'.$timersymb}; 
                   if ($start && $end) {
                       if (($start <= time) && ($end >= time)) {
                           unless (grep(/^\Q$block\E$/,@blockers)) {
                               push(@blockers,$block);
                               $triggered{$block} = {
                                                      start => $start,
                                                      end   => $end,
                                                      type  => $type,
                                                    };
                           }
                       }
                   }
               }
           }
       }
       foreach my $blocker (@blockers) {
           my ($staff_name,$staff_dom,$title,$blocks) =
               &parse_block_record($commblocks{$blocker});
           push(@{$$setters{$course}{'staff'}},[$staff_name,$staff_dom]);
           my ($start,$end,$triggertype);
           if ($blocker =~ m/^(\d+)____(\d+)$/) {
               ($start,$end) = ($1,$2);
           } elsif (ref($triggered{$blocker}) eq 'HASH') {
               $start = $triggered{$blocker}{'start'};
               $end = $triggered{$blocker}{'end'};
               $triggertype = $triggered{$blocker}{'type'};
           }
           if ($start) {
               push(@{$$setters{$course}{'times'}}, [$start,$end]);
               if ($triggertype) {
                   push(@{$$setters{$course}{'triggers'}},$triggertype);
               } else {
                   push(@{$$setters{$course}{'triggers'}},0);
               }
               if ( ($startblock == 0) || ($startblock > $start) ) {
                   $startblock = $start;
                   if ($triggertype) {
                       $triggerblock = $blocker;
                   }
               }
               if ( ($endblock == 0) || ($endblock < $end) ) {
                  $endblock = $end;
                  if ($triggertype) {
                      $triggerblock = $blocker;
                  }
             }              }
         }          }
     }      }
     return ($startblock,$endblock);      return ($startblock,$endblock,$triggerblock);
 }  }
   
 sub parse_block_record {  sub parse_block_record {
Line 4129  sub parse_block_record { Line 4557  sub parse_block_record {
 }  }
   
 sub blocking_status {  sub blocking_status {
   my ($activity,$uname,$udom) = @_;      my ($activity,$uname,$udom,$url) = @_;
   my %setters;      my %setters;
   
   # check for active blocking  
   my ($startblock,$endblock)=&blockcheck(\%setters,$activity,$uname,$udom);  
   
   my $blocked = $startblock && $endblock ? 1 : 0;  
   
   # caller just wants to know whether a block is active  # check for active blocking
   if (!wantarray) { return $blocked; }      my ($startblock,$endblock,$triggerblock) = 
           &blockcheck(\%setters,$activity,$uname,$udom,$url);
   # build a link to a popup window containing the details      my $blocked = 0;
   my $querystring  = "?activity=$activity";      if ($startblock && $endblock) {
   # $uname and $udom decide whose portfolio the user is trying to look at          $blocked = 1;
      $querystring .= "&amp;udom=$udom"      if $udom;      }
      $querystring .= "&amp;uname=$uname"    if $uname;  
   # caller just wants to know whether a block is active
   my $output .= <<'END_MYBLOCK';      if (!wantarray) { return $blocked; }
     function openWindow(url, wdwName, w, h, toolbar,scrollbar) {  
         var options = "width=" + w + ",height=" + h + ",";  # build a link to a popup window containing the details
         options += "resizable=yes,scrollbars="+scrollbar+",status=no,";      my $querystring  = "?activity=$activity";
         options += "menubar=no,toolbar="+toolbar+",location=no,directories=no";  # $uname and $udom decide whose portfolio the user is trying to look at
         var newWin = window.open(url, wdwName, options);      if ($activity eq 'port') {
         newWin.focus();          $querystring .= "&amp;udom=$udom"      if $udom;
     }          $querystring .= "&amp;uname=$uname"    if $uname;
       } elsif ($activity eq 'docs') {
           $querystring .= '&amp;url='.&HTML::Entities::encode($url,'&"');
       }
   
       my $output .= <<'END_MYBLOCK';
   function openWindow(url, wdwName, w, h, toolbar,scrollbar) {
       var options = "width=" + w + ",height=" + h + ",";
       options += "resizable=yes,scrollbars="+scrollbar+",status=no,";
       options += "menubar=no,toolbar="+toolbar+",location=no,directories=no";
       var newWin = window.open(url, wdwName, options);
       newWin.focus();
   }
 END_MYBLOCK  END_MYBLOCK
   
   $output = Apache::lonhtmlcommon::scripttag($output);      $output = Apache::lonhtmlcommon::scripttag($output);
       
   my $popupUrl = "/adm/blockingstatus/$querystring";      my $popupUrl = "/adm/blockingstatus/$querystring";
   my $text = mt('Communication Blocked');      my $text = &mt('Communication Blocked');
       if ($activity eq 'docs') {
   $output .= <<"END_BLOCK";          $text = &mt('Content Access Blocked');
       } elsif ($activity eq 'printout') {
           $text = &mt('Printing Blocked');
       }
       $output .= <<"END_BLOCK";
 <div class='LC_comblock'>  <div class='LC_comblock'>
   <a onclick='openWindow("$popupUrl","Blocking Table",600,300,"no","no");return false;' href='/adm/blockingstatus/$querystring'    <a onclick='openWindow("$popupUrl","Blocking Table",600,300,"no","no");return false;' href='/adm/blockingstatus/$querystring'
   title='$text'>    title='$text'>
Line 4172  END_MYBLOCK Line 4611  END_MYBLOCK
   
 END_BLOCK  END_BLOCK
   
   return ($blocked, $output);      return ($blocked, $output);
 }  }
   
 ###############################################  ###############################################
Line 4282  sub get_domainconf { Line 4721  sub get_domainconf {
                     if (ref($domconfig{'login'}{$key}) eq 'HASH') {                      if (ref($domconfig{'login'}{$key}) eq 'HASH') {
                         if ($key eq 'loginvia') {                          if ($key eq 'loginvia') {
                             if (ref($domconfig{'login'}{'loginvia'}) eq 'HASH') {                              if (ref($domconfig{'login'}{'loginvia'}) eq 'HASH') {
                                 my @ids = &Apache::lonnet::current_machine_ids();                                  foreach my $hostname (keys(%{$domconfig{'login'}{'loginvia'}})) {
                                 foreach my $hostname (@ids) {  
                                     if (ref($domconfig{'login'}{'loginvia'}{$hostname}) eq 'HASH') {                                      if (ref($domconfig{'login'}{'loginvia'}{$hostname}) eq 'HASH') {
                                         if ($domconfig{'login'}{'loginvia'}{$hostname}{'server'}) {                                          if ($domconfig{'login'}{'loginvia'}{$hostname}{'server'}) {
                                             my $server = $domconfig{'login'}{'loginvia'}{$hostname}{'server'};                                              my $server = $domconfig{'login'}{'loginvia'}{$hostname}{'server'};
Line 4292  sub get_domainconf { Line 4730  sub get_domainconf {
   
                                                 $designhash{$udom.'.login.loginvia_'.$hostname} = $server.':'.$domconfig{'login'}{'loginvia'}{$hostname}{'custompath'};                                                  $designhash{$udom.'.login.loginvia_'.$hostname} = $server.':'.$domconfig{'login'}{'loginvia'}{$hostname}{'custompath'};
                                             } else {                                              } else {
                                                  $designhash{$udom.'.login.loginvia_'.$hostname} = $server.':'.$domconfig{'login'}{'loginvia'}{$hostname}{'serverpath'};                                                  $designhash{$udom.'.login.loginvia_'.$hostname} = $server.':'.$domconfig{'login'}{'loginvia'}{$hostname}{'serverpath'};
                                             }                                              }
                                             if ($domconfig{'login'}{'loginvia'}{$hostname}{'exempt'}) {                                              if ($domconfig{'login'}{'loginvia'}{$hostname}{'exempt'}) {
                                                 $designhash{$udom.'.login.loginvia_exempt_'.$hostname} = $domconfig{'login'}{'loginvia'}{$hostname}{'exempt'};                                                  $designhash{$udom.'.login.loginvia_exempt_'.$hostname} = $domconfig{'login'}{'loginvia'}{$hostname}{'exempt'};
Line 4375  sub get_legacy_domconf { Line 4813  sub get_legacy_domconf {
             close($fh);              close($fh);
         }          }
     }      }
     if (-e '/home/httpd/html/adm/lonDomLogos/'.$udom.'.gif') {      if (-e $Apache::lonnet::perlvar{'lonDocRoot'}.'/adm/lonDomLogos/'.$udom.'.gif') {
         $legacyhash{$udom.'.login.domlogo'} = "/adm/lonDomLogos/$udom.gif";          $legacyhash{$udom.'.login.domlogo'} = "/adm/lonDomLogos/$udom.gif";
     }      }
     return %legacyhash;      return %legacyhash;
Line 4433  sub designparm { Line 4871  sub designparm {
         return $env{'environment.color.'.$which};          return $env{'environment.color.'.$which};
     }      }
     $domain=&determinedomain($domain);      $domain=&determinedomain($domain);
     my %domdesign = &get_domainconf($domain);      my %domdesign;
       unless ($domain eq 'public') {
           %domdesign = &get_domainconf($domain);
       }
     my $output;      my $output;
     if ($domdesign{$domain.'.'.$which} ne '') {      if ($domdesign{$domain.'.'.$which} ne '') {
         $output = $domdesign{$domain.'.'.$which};          $output = $domdesign{$domain.'.'.$which};
Line 4458  sub designparm { Line 4899  sub designparm {
   
 =item * &authorspace()  =item * &authorspace()
   
 Inputs: ./.  Inputs: $url (usually will be undef).
   
 Returns: Path to the Construction Space of the current user's  Returns: Path to Construction Space containing the resource or 
          accessed author space           directory being viewed (or for which action is being taken). 
          The author space will be that of the current user           If $url is provided, and begins /priv/<domain>/<uname>
          when accessing the own author space           the path will be that portion of the $context argument.
          and that of the co-author/assistent co-author           Otherwise the path will be for the author space of the current
          when accessing the co-author's/assistent co-author's           user when the current role is author, or for that of the 
          space           co-author/assistant co-author space when the current role 
            is co-author or assistant co-author.
   
 =cut  =cut
   
 sub authorspace {  sub authorspace {
       my ($url) = @_;
       if ($url ne '') {
           if ($url =~ m{^(/priv/$match_domain/$match_username/)}) {
              return $1;
           }
       }
     my $caname = '';      my $caname = '';
     if ($env{'request.role'} =~ /^ca|^aa/) {      my $cadom = '';
         (undef,$caname) =      if ($env{'request.role'} =~ /^(?:ca|aa)/) {
           ($cadom,$caname) =
             ($env{'request.role'}=~/($match_domain)\/($match_username)$/);              ($env{'request.role'}=~/($match_domain)\/($match_username)$/);
     } else {      } elsif ($env{'request.role'} =~ m{^au\./($match_domain)/}) {
         $caname = $env{'user.name'};          $caname = $env{'user.name'};
           $cadom = $env{'user.domain'};
     }      }
     return '/priv/'.$caname.'/';      if (($caname ne '') && ($cadom ne '')) {
           return "/priv/$cadom/$caname/";
       }
       return;
 }  }
   
 ##############################################  ##############################################
Line 4506  sub head_subbox { Line 4959  sub head_subbox {
   
 =item * &CSTR_pageheader()  =item * &CSTR_pageheader()
   
 Inputs: ./.  Input: (optional) filename from which breadcrumb trail is built.
          In most cases no input as needed, as $env{'request.filename'}
          is appropriate for use in building the breadcrumb trail.
   
 Returns: HTML div with CSTR path and recent box  Returns: HTML div with CSTR path and recent box
          To be included on Construction Space pages           To be included on Construction Space pages
Line 4514  Returns: HTML div with CSTR path and rec Line 4969  Returns: HTML div with CSTR path and rec
 =cut  =cut
   
 sub CSTR_pageheader {  sub CSTR_pageheader {
     # this is for resources; directories have customtitle, and crumbs      my ($trailfile) = @_;
             # and select recent are created in lonpubdir.pm        if ($trailfile eq '') {
     my ($uname,$thisdisfn)=          $trailfile = $env{'request.filename'};
         ($env{'request.filename'} =~ m|^/home/([^/]+)/public_html/(.*)|);      }
     my $formaction='/priv/'.$uname.'/'.$thisdisfn;  
     $formaction=~s/\/+/\//g;  # this is for resources; directories have customtitle, and crumbs
   # and select recent are created in lonpubdir.pm
   
       my $londocroot = $Apache::lonnet::perlvar{'lonDocRoot'};
       my ($udom,$uname,$thisdisfn)=
           ($trailfile =~ m{^\Q$londocroot\E/priv/([^/]+)/([^/]+)/(.*)$});
       my $formaction = "/priv/$udom/$uname/$thisdisfn";
       $formaction =~ s{/+}{/}g;
   
     my $parentpath = '';      my $parentpath = '';
     my $lastitem = '';      my $lastitem = '';
Line 4536  sub CSTR_pageheader { Line 4998  sub CSTR_pageheader {
         .'<b>'.&mt('Construction Space:').'</b> '          .'<b>'.&mt('Construction Space:').'</b> '
         .'<form name="dirs" method="post" action="'.$formaction          .'<form name="dirs" method="post" action="'.$formaction
         .'" target="_top">' #FIXME lonpubdir: target="_parent"          .'" target="_top">' #FIXME lonpubdir: target="_parent"
         .&Apache::lonhtmlcommon::crumbs($uname.'/'.$parentpath,'_top','/priv',undef,undef);          .&Apache::lonhtmlcommon::crumbs($uname.'/'.$parentpath,'_top','/priv/'.$udom,undef,undef);
   
     if ($lastitem) {      if ($lastitem) {
         $output .=          $output .=
Line 4592  Inputs: Line 5054  Inputs:
   
 =item * $bgcolor, used to override the bgcolor on a webpage to a specific value  =item * $bgcolor, used to override the bgcolor on a webpage to a specific value
   
 =item * $no_inline_link, if true and in remote mode, don't show the   
          'Switch To Inline Menu' link  
   
 =item * $args, optional argument valid values are  =item * $args, optional argument valid values are
             no_auto_mt_title -> prevents &mt()ing the title arg              no_auto_mt_title -> prevents &mt()ing the title arg
             inherit_jsmath -> when creating popup window in a page,              inherit_jsmath -> when creating popup window in a page,
                               should it have jsmath forced on by the                                should it have jsmath forced on by the
                               current page                                current page
   
   =item * $advtoolsref, optional argument, ref to an array containing
               inlineremote items to be added in "Functions" menu below
               breadcrumbs.
   
 =back  =back
   
 Returns: A uniform header for LON-CAPA web pages.    Returns: A uniform header for LON-CAPA web pages.  
Line 4612  other decorations will be returned. Line 5075  other decorations will be returned.
   
 sub bodytag {  sub bodytag {
     my ($title,$function,$addentries,$bodyonly,$domain,$forcereg,      my ($title,$function,$addentries,$bodyonly,$domain,$forcereg,
         $no_nav_bar,$bgcolor,$no_inline_link,$args)=@_;          $no_nav_bar,$bgcolor,$args,$advtoolsref)=@_;
   
     my $public;      my $public;
     if ((($env{'user.name'} eq 'public') && ($env{'user.domain'} eq 'public'))      if ((($env{'user.name'} eq 'public') && ($env{'user.domain'} eq 'public'))
Line 4654  sub bodytag { Line 5117  sub bodytag {
     }      }
   
     if (!$realm) { $realm='&nbsp;'; }      if (!$realm) { $realm='&nbsp;'; }
 # Set messages  
     my $messages=&domainlogo($domain);  
   
     my $extra_body_attr = &make_attr_string($forcereg,\%design);      my $extra_body_attr = &make_attr_string($forcereg,\%design);
   
Line 4671  sub bodytag { Line 5132  sub bodytag {
     if ($public) {      if ($public) {
  undef($role);   undef($role);
     } else {      } else {
  $name = &aboutmewrapper($name,$env{'user.name'},$env{'user.domain'});   $name = &aboutmewrapper($name,$env{'user.name'},$env{'user.domain'},
                                   undef,'LC_menubuttons_link');
     }      }
       
     my $titleinfo = '<h1>'.$title.'</h1>';      my $titleinfo = '<h1>'.$title.'</h1>';
     #      #
     # Extra info if you are the DC      # Extra info if you are the DC
Line 4689  sub bodytag { Line 5151  sub bodytag {
     $role = '<span class="LC_nobreak">('.$role.')</span>' if $role;      $role = '<span class="LC_nobreak">('.$role.')</span>' if $role;
     &get_unprocessed_cgi($ENV{'QUERY_STRING'}, ['inhibitmenu']);      &get_unprocessed_cgi($ENV{'QUERY_STRING'}, ['inhibitmenu']);
   
     if ($env{'environment.remote'} ne 'on') {  
         # No Remote  
         if ($no_nav_bar || $env{'form.inhibitmenu'} eq 'yes') {           if ($no_nav_bar || $env{'form.inhibitmenu'} eq 'yes') { 
             return $bodytag;              return $bodytag; 
         }          } 
   
         if ($env{'request.state'} eq 'construct') { $forcereg=1; }          if ($env{'request.state'} eq 'construct') { $forcereg=1; }
   
Line 4711  sub bodytag { Line 5171  sub bodytag {
                 <em>$realm</em> $dc_info</div>|;                  <em>$realm</em> $dc_info</div>|;
             return $bodytag;              return $bodytag;
         }          }
         if (($env{'request.noversionuri'} =~ m{^/adm/navmaps}) &&  
              ($env{'environment.remotenavmap'} eq 'on')) {  
             return $bodytag;  
         }  
   
         unless ($env{'request.symb'} =~ m/\.page___\d+___/) {          unless ($env{'request.symb'} =~ m/\.page___\d+___/) {
             $bodytag .= qq|<div id="LC_nav_bar">$name $role</div>|;              $bodytag .= qq|<div id="LC_nav_bar">$name $role</div>|;
Line 4736  sub bodytag { Line 5192  sub bodytag {
             $bodytag .= Apache::lonmenu::serverform();              $bodytag .= Apache::lonmenu::serverform();
             $bodytag .= Apache::lonhtmlcommon::scripttag('', 'end');              $bodytag .= Apache::lonhtmlcommon::scripttag('', 'end');
             if ($env{'request.state'} eq 'construct') {              if ($env{'request.state'} eq 'construct') {
                 $bodytag .= &Apache::lonmenu::innerregister($forcereg,'',                  $bodytag .= &Apache::lonmenu::innerregister($forcereg,
                                 $args->{'bread_crumbs'});                                  $args->{'bread_crumbs'});
             } elsif ($forcereg) {               } elsif ($forcereg) {
                 $bodytag .= &Apache::lonmenu::innerregister($forcereg);                  $bodytag .= &Apache::lonmenu::innerregister($forcereg,undef,
                                                               $args->{'group'});
               } else {
                   $bodytag .= 
                       &Apache::lonmenu::prepare_functions($env{'request.noversionuri'},
                                                           $forcereg,$args->{'group'},
                                                           $args->{'bread_crumbs'},
                                                           $advtoolsref);
             }              }
         }else{          }else{
             # this is to seperate menu from content when there's no secondary              # this is to seperate menu from content when there's no secondary
Line 4749  sub bodytag { Line 5212  sub bodytag {
         }          }
   
         return $bodytag;          return $bodytag;
     }  
   
 #  
 # Top frame rendering, Remote is up  
 #  
   
     my $imgsrc = $img;  
     if ($img =~ /^\/adm/) {  
         $imgsrc = &lonhttpdurl($img);  
     }  
     my $upperleft='<img src="'.$imgsrc.'" alt="'.$function.'" />';  
   
     # Explicit link to get inline menu  
     my $menu= ($no_inline_link?''  
        :'<a href="/adm/remote?action=collapse" target="_top">'.&mt('Switch to Inline Menu Mode').'</a>');  
   
     if ($dc_info) {  
         $dc_info = qq|<span class="LC_cusr_subheading">($dc_info)</span>|;  
     }  
   
     unless ($env{'form.inhibitmenu'}) {  
         $bodytag .= qq|<div id="LC_nav_bar">$name $role</div>  
                        <ol class="LC_primary_menu LC_right">  
                        <li>$menu</li>  
                        </ol><div id="LC_realm"> $realm $dc_info</div>|;  
     }  
   
     return(<<ENDBODY);  
 $bodytag  
 <table id="LC_title_bar" class="LC_with_remote">  
 <tr><td>$upperleft</td>  
     <td>$messages&nbsp;</td>  
 </tr>  
 <tr><td>$titleinfo $dc_info $menu</td>  
 </tr>  
 </table>  
 ENDBODY  
 }  }
   
 sub dc_courseid_toggle {  sub dc_courseid_toggle {
     my ($dc_info) = @_;      my ($dc_info) = @_;
     return ' <span id="dccidtext" class="LC_cusr_subheading LC_nobreak">'.      return ' <span id="dccidtext" class="LC_cusr_subheading LC_nobreak">'.
            '<a href="javascript:showCourseID();">'.             '<a href="javascript:showCourseID();" class="LC_menubuttons_link">'.
            &mt('(More ...)').'</a></span>'.             &mt('(More ...)').'</a></span>'.
            '<div id="dccid" class="LC_dccid">'.$dc_info.'</div>';             '<div id="dccid" class="LC_dccid">'.$dc_info.'</div>';
 }  }
Line 4817  sub make_attr_string { Line 5243  sub make_attr_string {
  delete($attr_ref->{$key});   delete($attr_ref->{$key});
     }      }
  }   }
  $attr_ref->{'onload'}  =   $attr_ref->{'onload'}  = $on_load;
     &Apache::lonmenu::loadevents().  $on_load;   $attr_ref->{'onunload'}= $on_unload;
  $attr_ref->{'onunload'}=  
     &Apache::lonmenu::unloadevents().$on_unload;  
     }  
   
 # Accessibility font enhance  
     if ($env{'browser.fontenhance'} eq 'on') {  
  my $style;  
  foreach my $key (keys(%{$attr_ref})) {  
     if (lc($key) eq 'style') {  
  $style.=$attr_ref->{$key}.';';  
  delete($attr_ref->{$key});  
     }  
  }  
  $attr_ref->{'style'}=$style.'; font-size: x-large;';  
     }      }
   
     my $attr_string;      my $attr_string;
Line 4862  i.e., $env{'internal.head.redirect'} exi Line 5274  i.e., $env{'internal.head.redirect'} exi
   
 sub endbodytag {  sub endbodytag {
     my ($args) = @_;      my ($args) = @_;
     my $endbodytag='</body>';      my $endbodytag;
       unless ((ref($args) eq 'HASH') && ($args->{'notbody'})) {
           $endbodytag='</body>';
       }
     $endbodytag=&Apache::lontexconvert::jsMath_process()."\n".$endbodytag;      $endbodytag=&Apache::lontexconvert::jsMath_process()."\n".$endbodytag;
     if ( exists( $env{'internal.head.redirect'} ) ) {      if ( exists( $env{'internal.head.redirect'} ) ) {
         if (!(ref($args) eq 'HASH' && $args->{'noredirectlink'})) {          if (!(ref($args) eq 'HASH' && $args->{'noredirectlink'})) {
Line 4910  sub standard_css { Line 5325  sub standard_css {
     my $mono                 = 'monospace';      my $mono                 = 'monospace';
     my $data_table_head      = $sidebg;      my $data_table_head      = $sidebg;
     my $data_table_light     = '#FAFAFA';      my $data_table_light     = '#FAFAFA';
     my $data_table_dark      = '#F0F0F0';      my $data_table_dark      = '#E0E0E0';
     my $data_table_darker    = '#CCCCCC';      my $data_table_darker    = '#CCCCCC';
     my $data_table_highlight = '#FFFF00';      my $data_table_highlight = '#FFFF00';
     my $mail_new             = '#FFBB77';      my $mail_new             = '#FFBB77';
Line 4930  sub standard_css { Line 5345  sub standard_css {
       $env{'browser.type'} eq 'safari'     ) ? '0 2px 0 2px'        $env{'browser.type'} eq 'safari'     ) ? '0 2px 0 2px'
                                              : '0 3px 0 4px';                                               : '0 3px 0 4px';
   
   
     return <<END;      return <<END;
   
 /* needed for iframe to allow 100% height in FF */  /* needed for iframe to allow 100% height in FF */
Line 4949  body { Line 5365  body {
 a:focus,  a:focus,
 a:focus img {  a:focus img {
   color: red;    color: red;
   background: yellow;  
 }  }
   
 form, .inline {  form, .inline {
Line 4996  form, .inline { Line 5411  form, .inline {
   text-decoration:none;    text-decoration:none;
 }  }
   
   .LC_setting {
     text-decoration:underline;
   }
   
 .LC_error {  .LC_error {
   color: red;    color: red;
   font-size: larger;  
 }  }
   
 .LC_warning,  .LC_warning {
     color: darkorange;
   }
   
 .LC_diff_removed {  .LC_diff_removed {
   color: red;    color: red;
 }  }
Line 5040  div.LC_confirm_box .LC_success img { Line 5461  div.LC_confirm_box .LC_success img {
 }  }
   
 .LC_discussion {  .LC_discussion {
   background: $tabbg;    background: $data_table_dark;
   border: 1px solid black;    border: 1px solid black;
   margin: 2px;    margin: 2px;
 }  }
   
 .LC_disc_action_links_bar {  
   background: $tabbg;  
   border: none;  
   margin: 4px;  
 }  
   
 .LC_disc_action_left {  .LC_disc_action_left {
     background: $sidebg;
   text-align: left;    text-align: left;
     padding: 4px;
     margin: 2px;
 }  }
   
 .LC_disc_action_right {  .LC_disc_action_right {
     background: $sidebg;
   text-align: right;    text-align: right;
     padding: 4px;
     margin: 2px;
 }  }
   
 .LC_disc_new_item {  .LC_disc_new_item {
   background: white;    background: white;
   border: 2px solid red;    border: 2px solid red;
   margin: 2px;    margin: 4px;
     padding: 4px;
 }  }
   
 .LC_disc_old_item {  .LC_disc_old_item {
   background: white;    background: white;
   border: 1px solid black;    margin: 4px;
   margin: 2px;    padding: 4px;
 }  }
   
 table.LC_pastsubmission {  table.LC_pastsubmission {
Line 5163  td.LC_table_cell_checkbox { Line 5585  td.LC_table_cell_checkbox {
   text-align: left;    text-align: left;
 }  }
   
 /* Preliminary fix to hide breadcrumbs inside remote control window */  .LC_head_subbox, .LC_actionbox {
 #LC_remote #LC_breadcrumbs {  
   display:none;  
 }  
   
 .LC_head_subbox {  
   clear:both;    clear:both;
   background: #F8F8F8; /* $sidebg; */    background: #F8F8F8; /* $sidebg; */
   border: 1px solid $sidebg;    border: 1px solid $sidebg;
   margin: 0 0 10px 0;          margin: 0 0 10px 0;
   padding: 3px;    padding: 3px;
   text-align: left;    text-align: left;
 }  }
Line 5195  td.LC_table_cell_checkbox { Line 5612  td.LC_table_cell_checkbox {
   vertical-align: middle;    vertical-align: middle;
 }  }
   
 li.LC_menubuttons_inline_text img,a {  li.LC_menubuttons_inline_text img {
   cursor:pointer;    cursor:pointer;
   text-decoration: none;    text-decoration: none;
 }  }
Line 5245  table.LC_nested { Line 5662  table.LC_nested {
   width: 100%;    width: 100%;
 }  }
   
 .ui-accordion,  
 .ui-accordion table.LC_data_table,  
 .ui-accordion table.LC_nested_outer{  
   border: 0px;  
   border-spacing: 0px;  
   margin: 3px;  
 }  
   
 table.LC_data_table tr th,  table.LC_data_table tr th,
 table.LC_calendar tr th,  table.LC_calendar tr th,
 table.LC_prior_tries tr th,  table.LC_prior_tries tr th,
Line 5368  table.LC_nested tr td.LC_right_item { Line 5777  table.LC_nested tr td.LC_right_item {
   text-align: right;    text-align: right;
 }  }
   
 .ui-accordion table.LC_nested tr.LC_odd_row td.LC_left_item,  
 .ui-accordion table.LC_nested tr.LC_even_row td.LC_left_item {  
   text-align: right;  
   width: 40%;  
   padding-right:10px;  
   vertical-align: top;  
   padding: 5px;  
 }  
   
 .ui-accordion table.LC_nested tr.LC_odd_row td.LC_right_item,  
 .ui-accordion table.LC_nested tr.LC_even_row td.LC_right_item {  
   text-align: left;  
   width: 60%;  
   padding: 2px 4px;  
 }  
   
 table.LC_nested tr.LC_odd_row td {  table.LC_nested tr.LC_odd_row td {
   background-color: #EEEEEE;    background-color: #EEEEEE;
 }  }
Line 5515  span.LC_current_location { Line 5908  span.LC_current_location {
   background: $pgbg;    background: $pgbg;
 }  }
   
   span.LC_current_nav_location {
     font-weight:bold;
     background: $sidebg;
   }
   
 span.LC_parm_menu_item {  span.LC_parm_menu_item {
   font-size: larger;    font-size: larger;
 }  }
Line 5710  table.LC_group_priv td { Line 6108  table.LC_group_priv td {
   padding: 0;    padding: 0;
 }  }
   
 table.LC_notify_front_page {  
   background: white;  
   border: 1px solid black;  
   padding: 8px;  
 }  
   
 table.LC_notify_front_page td {  
   padding: 8px;  
 }  
   
 .LC_navbuttons {  .LC_navbuttons {
   margin: 2ex 0ex 2ex 0ex;    margin: 2ex 0ex 2ex 0ex;
 }  }
Line 5896  div.LC_docs_entry_move { Line 6284  div.LC_docs_entry_move {
   
 table.LC_data_table tr > td.LC_docs_entry_commands,  table.LC_data_table tr > td.LC_docs_entry_commands,
 table.LC_data_table tr > td.LC_docs_entry_parameter {  table.LC_data_table tr > td.LC_docs_entry_parameter {
   background: #DDDDDD;  
   font-size: x-small;    font-size: x-small;
 }  }
   
Line 6026  div.LC_edit_problem_footer { Line 6413  div.LC_edit_problem_footer {
   font-weight: normal;    font-weight: normal;
   font-size:  medium;    font-size:  medium;
   margin: 2px;    margin: 2px;
     background-color: $sidebg;
 }  }
   
 div.LC_edit_problem_header,  div.LC_edit_problem_header,
Line 6042  div.LC_edit_problem_header_title { Line 6430  div.LC_edit_problem_header_title {
   font-size: larger;    font-size: larger;
   background: $tabbg;    background: $tabbg;
   padding: 3px;    padding: 3px;
     margin: 0 0 5px 0;
 }  }
   
 table.LC_edit_problem_header_title {  table.LC_edit_problem_header_title {
Line 6079  div.LC_createcourse { Line 6468  div.LC_createcourse {
   display:none;    display:none;
 }  }
   
 a:hover,  
 ol.LC_primary_menu a:hover,  ol.LC_primary_menu a:hover,
 ol#LC_MenuBreadcrumbs a:hover,  ol#LC_MenuBreadcrumbs a:hover,
 ol#LC_PathBreadcrumbs a:hover,  ol#LC_PathBreadcrumbs a:hover,
Line 6170  fieldset > legend { Line 6558  fieldset > legend {
   font-style: normal;    font-style: normal;
 }  }
   
 /* Preliminary fix to hide nav_bar inside bookmarks window */  
 #LC_bookmarks #LC_nav_bar {  
   display:none;  
 }  
   
 ol.LC_primary_menu {  ol.LC_primary_menu {
   float: right;    float: right;
   margin: 0;    margin: 0;
     padding: 0;
   background-color: $pgbg_or_bgcolor;    background-color: $pgbg_or_bgcolor;
 }  }
   
 ol.LC_primary_menu a.LC_new_message {  
   font-weight:bold;  
   color: darkred;  
 }  
   
 ol#LC_PathBreadcrumbs {  ol#LC_PathBreadcrumbs {
   margin: 0;    margin: 0;
 }  }
   
 ol.LC_primary_menu li {  ol.LC_primary_menu li {
   display: inline;    color: RGB(80, 80, 80);
   padding: 5px 5px 0 10px;    vertical-align: middle;
     text-align: left;
     list-style: none;
     float: left;
   }
   
   ol.LC_primary_menu li a {
     display: block;
     margin: 0;
     padding: 0 5px 0 10px;
     text-decoration: none;
   }
   
   ol.LC_primary_menu li ul {
     display: none;
     width: 10em;
     background-color: $data_table_light;
   }
   
   ol.LC_primary_menu li:hover ul, ol.LC_primary_menu li.hover ul {
     display: block;
     position: absolute;
     margin: 0;
     padding: 0;
     z-index: 2;
   }
   
   ol.LC_primary_menu li:hover li, ol.LC_primary_menu li.hover li {
     font-size: 90%;
   vertical-align: top;    vertical-align: top;
     float: none;
     border-left: 1px solid black;
     border-right: 1px solid black;
   }
   
   ol.LC_primary_menu li:hover li a, ol.LC_primary_menu li.hover li a {
     background-color:$data_table_light;
   }
   
   ol.LC_primary_menu li li a:hover {
      color:$button_hover;
      background-color:$data_table_dark;
 }  }
   
 ol.LC_primary_menu li img {  ol.LC_primary_menu li img {
   vertical-align: bottom;    vertical-align: bottom;
   height: 1.1em;    height: 1.1em;
     margin: 0.2em 0 0 0;
 }  }
   
 ol.LC_primary_menu a {  ol.LC_primary_menu a {
Line 6206  ol.LC_primary_menu a { Line 6626  ol.LC_primary_menu a {
   text-decoration: none;    text-decoration: none;
 }  }
   
   ol.LC_primary_menu a.LC_new_message {
     font-weight:bold;
     color: darkred;
   }
   
 ol.LC_docs_parameters {  ol.LC_docs_parameters {
   margin-left: 0;    margin-left: 0;
   padding: 0;    padding: 0;
Line 6231  ol.LC_docs_parameters li.LC_docs_paramet Line 6656  ol.LC_docs_parameters li.LC_docs_paramet
 }  }
   
 ul#LC_secondary_menu {  ul#LC_secondary_menu {
   clear: both;    clear: right;
   color: $fontmenu;    color: $fontmenu;
   background: $tabbg;    background: $tabbg;
   list-style: none;    list-style: none;
Line 6239  ul#LC_secondary_menu { Line 6664  ul#LC_secondary_menu {
   margin: 0;    margin: 0;
   width: 100%;    width: 100%;
   text-align: left;    text-align: left;
     float: left;
 }  }
   
 ul#LC_secondary_menu li {  ul#LC_secondary_menu li {
   font-weight: bold;    font-weight: bold;
   line-height: 1.8em;    line-height: 1.8em;
     border-right: 1px solid black;
     float: left;
   }
   
   ul#LC_secondary_menu li.LC_hoverable:hover, ul#LC_secondary_menu li.hover {
     background-color: $data_table_light;
   }
   
   ul#LC_secondary_menu li a {
   padding: 0 0.8em;    padding: 0 0.8em;
   }
   
   ul#LC_secondary_menu li ul {
     display: none;
   }
   
   ul#LC_secondary_menu li:hover ul, ul#LC_secondary_menu li.hover ul {
     display: block;
     position: absolute;
     margin: 0;
     padding: 0;
     list-style:none;
     float: none;
     background-color: $data_table_light;
     z-index: 2;
     margin-left: -1px;
   }
   
   ul#LC_secondary_menu li ul li {
     font-size: 90%;
     vertical-align: top;
     border-left: 1px solid black;
   border-right: 1px solid black;    border-right: 1px solid black;
   display: inline;    background-color: $data_table_light
   vertical-align: middle;    list-style:none;
     float: none;
   }
   
   ul#LC_secondary_menu li ul li:hover, ul#LC_secondary_menu li ul li.hover {
     background-color: $data_table_dark;
 }  }
   
 ul.LC_TabContent {  ul.LC_TabContent {
Line 6255  ul.LC_TabContent { Line 6717  ul.LC_TabContent {
   background: $sidebg;    background: $sidebg;
   border-bottom: solid 1px $lg_border_color;    border-bottom: solid 1px $lg_border_color;
   list-style:none;    list-style:none;
   margin: 0 -10px;    margin: -1px -10px 0 -10px;
   padding: 0;    padding: 0;
 }  }
   
Line 6278  ul.LC_TabContent li { Line 6740  ul.LC_TabContent li {
   padding: 0 16px 0 10px;    padding: 0 16px 0 10px;
   background-color:$tabbg;    background-color:$tabbg;
   border-bottom:solid 1px $lg_border_color;    border-bottom:solid 1px $lg_border_color;
   border-right: solid 1px $font;    border-left: solid 1px $font;
 }  }
   
 ul.LC_TabContent .right {  ul.LC_TabContent .right {
Line 6318  ul.LC_TabContent li.active a { Line 6780  ul.LC_TabContent li.active a {
   background:#FFFFFF;    background:#FFFFFF;
   outline: none;    outline: none;
 }  }
   
   ul.LC_TabContent li.goback {
     float: left;
     border-left: none;
   }
   
 #maincoursedoc {  #maincoursedoc {
   clear:both;    clear:both;
 }  }
Line 6348  ul.LC_TabContentBigger li a { Line 6816  ul.LC_TabContentBigger li a {
   text-align: center;    text-align: center;
   display: block;    display: block;
   text-decoration: none;    text-decoration: none;
   outline: none;    outline: none;  
 }  }
   
 ul.LC_TabContentBigger li.active a {  ul.LC_TabContentBigger li.active a {
Line 6372  ul.LC_TabContentBigger li.active b { Line 6840  ul.LC_TabContentBigger li.active b {
   background:url('/adm/lonIcons/tabbgright.gif') right top no-repeat;    background:url('/adm/lonIcons/tabbgright.gif') right top no-repeat;
   color:$font;    color:$font;
   border: 0;    border: 0;
   cursor:default;  
 }  }
   
   
 ul.LC_CourseBreadcrumbs {  ul.LC_CourseBreadcrumbs {
   background: $sidebg;    background: $sidebg;
   line-height: 32px;    height: 2em;
   padding-left: 10px;    padding-left: 10px;
   margin: 0 0 10px 0;    margin: 0;
   list-style-position: inside;    list-style-position: inside;
   
 }  }
   
 ol#LC_MenuBreadcrumbs,  ol#LC_MenuBreadcrumbs,
Line 6423  ol#LC_PathBreadcrumbs li a { Line 6890  ol#LC_PathBreadcrumbs li a {
   padding: 0 10px 10px 10px;    padding: 0 10px 10px 10px;
 }  }
   
   .LC_DocsBox {
     border: solid 1px $lg_border_color;
     padding: 0 0 10px 10px;
   }
   
 .LC_AboutMe_Image {  .LC_AboutMe_Image {
   float:left;    float:left;
   margin-right:10px;    margin-right:10px;
Line 6543  a#LC_content_toolbar_firsthomework { Line 7015  a#LC_content_toolbar_firsthomework {
   background-image:url(/res/adm/pages/open-first-problem.gif);    background-image:url(/res/adm/pages/open-first-problem.gif);
 }  }
   
 a#LC_content_toolbar_launchnav {  
   background-image:url(/res/adm/pages/start-navigation.gif);  
 }  
   
 a#LC_content_toolbar_closenav {  
   background-image:url(/res/adm/pages/close-navigation.gif);  
 }  
   
 a#LC_content_toolbar_everything {  a#LC_content_toolbar_everything {
   background-image:url(/res/adm/pages/show-all.gif);    background-image:url(/res/adm/pages/show-all.gif);
 }  }
Line 6571  a#LC_content_toolbar_changefolder_toggle Line 7035  a#LC_content_toolbar_changefolder_toggle
   background-image:url(/res/adm/pages/open-all-folders.gif);    background-image:url(/res/adm/pages/open-all-folders.gif);
 }  }
   
   a#LC_content_toolbar_edittoplevel {
     background-image:url(/res/adm/pages/edittoplevel.gif);
   }
   
 ul#LC_toolbar li a:hover {  ul#LC_toolbar li a:hover {
   background-position: bottom center;    background-position: bottom center;
 }  }
Line 6581  ul#LC_toolbar { Line 7049  ul#LC_toolbar {
   list-style:none;    list-style:none;
   position:relative;    position:relative;
   background-color:white;    background-color:white;
     overflow: auto;
 }  }
   
 ul#LC_toolbar li {  ul#LC_toolbar li {
Line 6590  ul#LC_toolbar li { Line 7059  ul#LC_toolbar li {
   float: left;    float: left;
   display:inline;    display:inline;
   vertical-align:middle;    vertical-align:middle;
     white-space: nowrap;
 }  }
   
   
Line 6635  ul.LC_funclist li { Line 7105  ul.LC_funclist li {
   line-height: 150%;    line-height: 150%;
 }  }
   
 .ui-accordion .LC_advanced_toggle {  .LC_hidden {
   float: right;    display: none;
   font-size: 90%;  
   padding: 0px 4px  
 }  }
   
   .LCmodal-overlay {
    position:fixed;
    top:0;
    right:0;
    bottom:0;
    left:0;
    height:100%;
    width:100%;
    margin:0;
    padding:0;
    background:#999;
    opacity:.75;
    filter: alpha(opacity=75);
    -moz-opacity: 0.75;
    z-index:101;
   }
   
   * html .LCmodal-overlay {   
    position: absolute;
    height: expression(document.body.scrollHeight > document.body.offsetHeight ? document.body.scrollHeight : document.body.offsetHeight + 'px');
   }
   
   .LCmodal-window {
    position:fixed;
    top:50%;
    left:50%;
    margin:0;
    padding:0;
    z-index:102;
    }
   
   * html .LCmodal-window {
    position:absolute;
   }
   
   .LCclose-window {
    position:absolute;
    width:32px;
    height:32px;
    right:8px;
    top:8px;
    background:transparent url('/res/adm/pages/process-stop.png') no-repeat scroll right top;
    text-indent:-99999px;
    overflow:hidden;
    cursor:pointer;
   }
   
   /*
     styles used by TTH when "Default set of options to pass to tth/m
     when converting TeX" in course settings has been set
   
     option passed: -t
   
   */
   
   td div.comp { margin-top: -0.6ex; margin-bottom: -1ex;}
   td div.comb { margin-top: -0.6ex; margin-bottom: -.6ex;}
   td div.hrcomp { line-height: 0.9; margin-top: -0.8ex; margin-bottom: -1ex;}
   td div.norm {line-height:normal;}
   
   /*
     option passed -y3
   */
   
   span.roman {font-family: serif; font-style: normal; font-weight: normal;}
   span.overacc2 {position: relative;  left: .8em; top: -1.2ex;}
   span.overacc1 {position: relative;  left: .6em; top: -1.2ex;}
   
 END  END
 }  }
   
Line 6689  sub headtag { Line 7225  sub headtag {
  '<head>'.   '<head>'.
  &font_settings();   &font_settings();
   
       my $inhibitprint = &print_suppression();
   
     if (!$args->{'frameset'}) {      if (!$args->{'frameset'}) {
  $result .= &Apache::lonhtmlcommon::htmlareaheaders();   $result .= &Apache::lonhtmlcommon::htmlareaheaders();
     }      }
     if ($args->{'force_register'}) {      if ($args->{'force_register'} && $env{'request.noversionuri'} !~ m{^/res/adm/pages/}) {
  $result .= &Apache::lonmenu::registerurl(1);          $result .= Apache::lonxml::display_title();
     }      }
     if (!$args->{'no_nav_bar'}       if (!$args->{'no_nav_bar'} 
  && !$args->{'only_body'}   && !$args->{'only_body'}
  && !$args->{'frameset'}) {   && !$args->{'frameset'}) {
  $result .= &help_menu_js();   $result .= &help_menu_js();
           $result.=&modal_window();
           $result.=&togglebox_script();
           $result.=&wishlist_window();
           $result.=&LCprogressbarUpdate_script();
       } else {
           if ($args->{'add_modal'}) {
              $result.=&modal_window();
           }
           if ($args->{'add_wishlist'}) {
              $result.=&wishlist_window();
           }
           if ($args->{'add_togglebox'}) {
              $result.=&togglebox_script();
           }
           if ($args->{'add_progressbar'}) {
              $result.=&LCprogressbarUpdate_script();
           }
     }      }
   
     if (ref($args->{'redirect'})) {      if (ref($args->{'redirect'})) {
  my ($time,$url,$inhibit_continue) = @{$args->{'redirect'}};   my ($time,$url,$inhibit_continue) = @{$args->{'redirect'}};
  $url = &Apache::lonenc::check_encrypt($url);   $url = &Apache::lonenc::check_encrypt($url);
Line 6718  ADDMETA Line 7272  ADDMETA
     if (!$args->{'no_auto_mt_title'}) { $title = &mt($title); }      if (!$args->{'no_auto_mt_title'}) { $title = &mt($title); }
     $result .= '<title> LON-CAPA '.$title.'</title>'      $result .= '<title> LON-CAPA '.$title.'</title>'
  .'<link rel="stylesheet" type="text/css" href="'.$url.'" />'   .'<link rel="stylesheet" type="text/css" href="'.$url.'" />'
           .$inhibitprint
  .$head_extra;   .$head_extra;
     return $result;      return $result.'</head>';
 }  }
   
 =pod  =pod
Line 6743  sub font_settings { Line 7298  sub font_settings {
   
 =pod  =pod
   
   =item * &print_suppression()
   
   In course context returns css which causes the body to be blank when media="print",
   if printout generation is unavailable for the current resource.
   
   This could be because:
   
   (a) printstartdate is in the future
   
   (b) printenddate is in the past
   
   (c) there is an active exam block with "printout"
   functionality blocked
   
   Users with pav, pfo or evb privileges are exempt.
   
   Inputs: none
   
   =cut
   
   
   sub print_suppression {
       my $noprint;
       if ($env{'request.course.id'}) {
           my $scope = $env{'request.course.id'};
           if ((&Apache::lonnet::allowed('pav',$scope)) ||
               (&Apache::lonnet::allowed('pfo',$scope))) {
               return;
           }
           if ($env{'request.course.sec'} ne '') {
               $scope .= "/$env{'request.course.sec'}";
               if ((&Apache::lonnet::allowed('pav',$scope)) ||
                   (&Apache::lonnet::allowed('pfo',$scope))) {
                   return;
               }
           }
           my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
           my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
           my $blocked = &blocking_status('printout',$cnum,$cdom);
           if ($blocked) {
               my $checkrole = "cm./$cdom/$cnum";
               if ($env{'request.course.sec'} ne '') {
                   $checkrole .= "/$env{'request.course.sec'}";
               }
               unless ((&Apache::lonnet::allowed('evb',undef,undef,$checkrole)) &&
                       ($env{'request.role'} !~ m{^st\./$cdom/$cnum})) {
                   $noprint = 1;
               }
           }
           unless ($noprint) {
               my $symb = &Apache::lonnet::symbread();
               if ($symb ne '') {
                   my $navmap = Apache::lonnavmaps::navmap->new();
                   if (ref($navmap)) {
                       my $res = $navmap->getBySymb($symb);
                       if (ref($res)) {
                           if (!$res->resprintable()) {
                               $noprint = 1;
                           }
                       }
                   }
               }
           }
           if ($noprint) {
               return <<"ENDSTYLE";
   <style type="text/css" media="print">
       body { display:none }
   </style>
   ENDSTYLE
           }
       }
       return;
   }
   
   =pod
   
 =item * &xml_begin()  =item * &xml_begin()
   
 Returns the needed doctype and <html>  Returns the needed doctype and <html>
Line 6772  sub xml_begin { Line 7403  sub xml_begin {
   
 =pod  =pod
   
 =item * &endheadtag()  
   
 Returns a uniform </head> for LON-CAPA web pages.  
   
 Inputs: none  
   
 =cut  
   
 sub endheadtag {  
     return '</head>';  
 }  
   
 =pod  
   
 =item * &head()  
   
 Returns a uniform complete <head>..</head> section for LON-CAPA web pages.  
   
 Inputs:  
   
 =over 4  
   
 $title - optional title for the page  
   
 $head_extra - optional extra HTML to put inside the <head>  
   
 =back  
   
 =cut  
   
 sub head {  
     my ($title,$head_extra,$args) = @_;  
     return &headtag($title,$head_extra,$args).&endheadtag();  
 }  
   
 =pod  
   
 =item * &start_page()  =item * &start_page()
   
 Returns a complete <html> .. <body> section for LON-CAPA web pages.  Returns a complete <html> .. <body> section for LON-CAPA web pages.
Line 6846  $args - additional optional args support Line 7440  $args - additional optional args support
              skip_phases    -> hash ref of                skip_phases    -> hash ref of 
                                     head -> skip the <html><head> generation                                      head -> skip the <html><head> generation
                                     body -> skip all <body> generation                                      body -> skip all <body> generation
              no_inline_link -> if true and in remote mode, don't show the   
                                     'Switch To Inline Menu' link  
              no_auto_mt_title -> prevent &mt()ing the title arg               no_auto_mt_title -> prevent &mt()ing the title arg
              inherit_jsmath -> when creating popup window in a page,               inherit_jsmath -> when creating popup window in a page,
                                     should it have jsmath forced on by the                                      should it have jsmath forced on by the
                                     current page                                      current page
              bread_crumbs ->             Array containing breadcrumbs               bread_crumbs ->             Array containing breadcrumbs
              bread_crumbs_component ->  if exists show it as headline else show only the breadcrumbs               bread_crumbs_component ->  if exists show it as headline else show only the breadcrumbs
                group          -> includes the current group, if page is for a 
                                  specific group  
   
 =back  =back
   
Line 6864  $args - additional optional args support Line 7458  $args - additional optional args support
 sub start_page {  sub start_page {
     my ($title,$head_extra,$args) = @_;      my ($title,$head_extra,$args) = @_;
     #&Apache::lonnet::logthis("start_page ".join(':',caller(0)));      #&Apache::lonnet::logthis("start_page ".join(':',caller(0)));
     my %head_args;  
     foreach my $arg ('redirect','force_register','domain','function',  
      'bgcolor','frameset','no_nav_bar','only_body',  
      'no_auto_mt_title') {  
  if (defined($args->{$arg})) {  
     $head_args{$arg} = $args->{$arg};  
  }  
     }  
   
     $env{'internal.start_page'}++;      $env{'internal.start_page'}++;
     my $result;      my ($result,@advtools);
   
     if (! exists($args->{'skip_phases'}{'head'}) ) {      if (! exists($args->{'skip_phases'}{'head'}) ) {
  $result.=          $result .= &xml_begin() . &headtag($title, $head_extra, $args);
     &xml_begin().  
     &headtag($title,$head_extra,\%head_args).&endheadtag();  
     }      }
           
     if (! exists($args->{'skip_phases'}{'body'}) ) {      if (! exists($args->{'skip_phases'}{'body'}) ) {
Line 6892  sub start_page { Line 7477  sub start_page {
                          $args->{'function'},       $args->{'add_entries'},                           $args->{'function'},       $args->{'add_entries'},
                          $args->{'only_body'},      $args->{'domain'},                           $args->{'only_body'},      $args->{'domain'},
                          $args->{'force_register'}, $args->{'no_nav_bar'},                           $args->{'force_register'}, $args->{'no_nav_bar'},
                          $args->{'bgcolor'},        $args->{'no_inline_link'},                           $args->{'bgcolor'},        $args,
                          $args);                           \@advtools);
         }          }
     }      }
   
Line 6909  sub start_page { Line 7494  sub start_page {
     #            $result .= &build_functionlist();      #            $result .= &build_functionlist();
     #}      #}
   
     # Don't add anything more if only_body wanted      # Don't add anything more if only_body wanted or in const space
     return $result if $args->{'only_body'};      return $result if    $args->{'only_body'} 
                         || $env{'request.state'} eq 'construct';
   
     #Breadcrumbs for Construction Space provided by &bodytag.   
     if (($env{'environment.remote'} eq 'off') && ($env{'request.state'} eq 'construct')) {  
         return $result;  
     }  
    
     #Breadcrumbs      #Breadcrumbs
     if (exists($args->{'bread_crumbs'}) or exists($args->{'bread_crumbs_component'})) {      if (exists($args->{'bread_crumbs'}) or exists($args->{'bread_crumbs_component'})) {
  &Apache::lonhtmlcommon::clear_breadcrumbs();   &Apache::lonhtmlcommon::clear_breadcrumbs();
Line 6926  sub start_page { Line 7507  sub start_page {
  &Apache::lonhtmlcommon::add_breadcrumb($crumb);   &Apache::lonhtmlcommon::add_breadcrumb($crumb);
  }   }
  }   }
                   # if @advtools array contains items add then to the breadcrumbs
                   if (@advtools > 0) {
                       &Apache::lonmenu::advtools_crumbs(@advtools);
                   }
   
  #if bread_crumbs_component exists show it as headline else show only the breadcrumbs   #if bread_crumbs_component exists show it as headline else show only the breadcrumbs
  if(exists($args->{'bread_crumbs_component'})){   if(exists($args->{'bread_crumbs_component'})){
Line 6937  sub start_page { Line 7522  sub start_page {
     return $result;      return $result;
 }  }
   
   
 =pod  
   
 =item * &head()  
   
 Returns a complete </body></html> section for LON-CAPA web pages.  
   
 Inputs:         $args - additional optional args supported are:  
                  js_ready     -> return a string ready for being used in   
                                  a javascript writeln  
                  html_encode  -> return a string ready for being used in   
                                  a html attribute  
                  frameset     -> if true will start with a <frameset>  
                                  rather than <body>  
                  dicsussion   -> if true will get discussion from  
                                   lonxml::xmlend  
                                  (you can pass the target and parser arguments  
                                   through optional 'target' and 'parser' args  
                                   to this routine)  
   
 =cut  
   
 sub end_page {  sub end_page {
     my ($args) = @_;      my ($args) = @_;
     $env{'internal.end_page'}++;      $env{'internal.end_page'}++;
Line 6971  sub end_page { Line 7534  sub end_page {
  }   }
  $result .= &Apache::lonxml::xmlend($target,$parser);   $result .= &Apache::lonxml::xmlend($target,$parser);
     }      }
   
     if ($args->{'frameset'}) {      if ($args->{'frameset'}) {
  $result .= '</frameset>';   $result .= '</frameset>';
     } else {      } else {
  $result .= &endbodytag($args);   $result .= &endbodytag($args);
     }      }
     $result .= "\n</html>";      unless ($args->{'notbody'}) {
           $result .= "\n</html>";
       }
   
     if ($args->{'js_ready'}) {      if ($args->{'js_ready'}) {
  $result = &js_ready($result);   $result = &js_ready($result);
Line 6990  sub end_page { Line 7554  sub end_page {
     return $result;      return $result;
 }  }
   
   sub wishlist_window {
       return(<<'ENDWISHLIST');
   <script type="text/javascript">
   // <![CDATA[
   // <!-- BEGIN LON-CAPA Internal
   function set_wishlistlink(title, path) {
       if (!title) {
           title = document.title;
           title = title.replace(/^LON-CAPA /,'');
       }
       if (!path) {
           path = location.pathname;
       }
       Win = window.open('/adm/wishlist?mode=newLink&setTitle='+title+'&setPath='+path,
                         'wishlistNewLink','width=560,height=350,scrollbars=0');
   }
   // END LON-CAPA Internal -->
   // ]]>
   </script>
   ENDWISHLIST
   }
   
   sub modal_window {
       return(<<'ENDMODAL');
   <script type="text/javascript">
   // <![CDATA[
   // <!-- BEGIN LON-CAPA Internal
   var modalWindow = {
    parent:"body",
    windowId:null,
    content:null,
    width:null,
    height:null,
    close:function()
    {
           $(".LCmodal-window").remove();
           $(".LCmodal-overlay").remove();
    },
    open:function()
    {
    var modal = "";
    modal += "<div class=\"LCmodal-overlay\"></div>";
    modal += "<div id=\"" + this.windowId + "\" class=\"LCmodal-window\" style=\"width:" + this.width + "px; height:" + this.height + "px; margin-top:-" + (this.height / 2) + "px; margin-left:-" + (this.width / 2) + "px;\">";
    modal += this.content;
    modal += "</div>";
   
    $(this.parent).append(modal);
   
    $(".LCmodal-window").append("<a class=\"LCclose-window\"></a>");
    $(".LCclose-window").click(function(){modalWindow.close();});
    $(".LCmodal-overlay").click(function(){modalWindow.close();});
    }
   };
    var openMyModal = function(source,width,height,scrolling)
    {
    modalWindow.windowId = "myModal";
    modalWindow.width = width;
    modalWindow.height = height;
    modalWindow.content = "<iframe width='"+width+"' height='"+height+"' frameborder='0' scrolling='"+scrolling+"' allowtransparency='true' src='" + source + "'>&lt/iframe>";
    modalWindow.open();
    };
   // END LON-CAPA Internal -->
   // ]]>
   </script>
   ENDMODAL
   }
   
   sub modal_link {
       my ($link,$linktext,$width,$height,$target,$scrolling,$title)=@_;
       unless ($width) { $width=480; }
       unless ($height) { $height=400; }
       unless ($scrolling) { $scrolling='yes'; }
       my $target_attr;
       if (defined($target)) {
           $target_attr = 'target="'.$target.'"';
       }
       return <<"ENDLINK";
   <a href="$link" $target_attr title="$title" onclick="javascript:openMyModal('$link',$width,$height,'$scrolling'); return false;">
              $linktext</a>
   ENDLINK
   }
   
   sub modal_adhoc_script {
       my ($funcname,$width,$height,$content)=@_;
       return (<<ENDADHOC);
   <script type="text/javascript">
   // <![CDATA[
           var $funcname = function()
           {
                   modalWindow.windowId = "myModal";
                   modalWindow.width = $width;
                   modalWindow.height = $height;
                   modalWindow.content = '$content';
                   modalWindow.open();
           };  
   // ]]>
   </script>
   ENDADHOC
   }
   
   sub modal_adhoc_inner {
       my ($funcname,$width,$height,$content)=@_;
       my $innerwidth=$width-20;
       $content=&js_ready(
                  &start_page('Dialog',undef,{'only_body'=>1,'bgcolor'=>'#FFFFFF'}).
                    &start_scrollbox($width.'px',$innerwidth.'px',$height.'px').
                       $content.
                    &end_scrollbox().
                  &end_page()
                );
       return &modal_adhoc_script($funcname,$width,$height,$content);
   }
   
   sub modal_adhoc_window {
       my ($funcname,$width,$height,$content,$linktext)=@_;
       return &modal_adhoc_inner($funcname,$width,$height,$content).
              "<a href=\"javascript:$funcname();void(0);\">".$linktext."</a>";
   }
   
   sub modal_adhoc_launch {
       my ($funcname,$width,$height,$content)=@_;
       return &modal_adhoc_inner($funcname,$width,$height,$content).(<<ENDLAUNCH);
   <script type="text/javascript">
   // <![CDATA[
   $funcname();
   // ]]>
   </script>
   ENDLAUNCH
   }
   
   sub modal_adhoc_close {
       return (<<ENDCLOSE);
   <script type="text/javascript">
   // <![CDATA[
   modalWindow.close();
   // ]]>
   </script>
   ENDCLOSE
   }
   
   sub togglebox_script {
      return(<<ENDTOGGLE);
   <script type="text/javascript"> 
   // <![CDATA[
   function LCtoggleDisplay(id,hidetext,showtext) {
      link = document.getElementById(id + "link").childNodes[0];
      with (document.getElementById(id).style) {
         if (display == "none" ) {
             display = "inline";
             link.nodeValue = hidetext;
           } else {
             display = "none";
             link.nodeValue = showtext;
          }
      }
   }
   // ]]>
   </script>
   ENDTOGGLE
   }
   
   sub start_togglebox {
       my ($id,$heading,$headerbg,$hidetext,$showtext)=@_;
       unless ($heading) { $heading=''; } else { $heading.=' '; }
       unless ($showtext) { $showtext=&mt('show'); }
       unless ($hidetext) { $hidetext=&mt('hide'); }
       unless ($headerbg) { $headerbg='#FFFFFF'; }
       return &start_data_table().
              &start_data_table_header_row().
              '<td bgcolor="'.$headerbg.'">'.$heading.
              '[<a id="'.$id.'link" href="javascript:LCtoggleDisplay(\''.$id.'\',\''.$hidetext.'\',\''.
              $showtext.'\')">'.$showtext.'</a>]</td>'.
              &end_data_table_header_row().
              '<tr id="'.$id.'" style="display:none""><td>';
   }
   
   sub end_togglebox {
       return '</td></tr>'.&end_data_table();
   }
   
   sub LCprogressbar_script {
      my ($id)=@_;
      return(<<ENDPROGRESS);
   <script type="text/javascript">
   // <![CDATA[
   \$('#progressbar$id').progressbar({
     value: 0,
     change: function(event, ui) {
       var newVal = \$(this).progressbar('option', 'value');
       \$('.pblabel', this).text(LCprogressTxt);
     }
   });
   // ]]>
   </script>
   ENDPROGRESS
   }
   
   sub LCprogressbarUpdate_script {
      return(<<ENDPROGRESSUPDATE);
   <style type="text/css">
   .ui-progressbar { position:relative; }
   .pblabel { position: absolute; width: 100%; text-align: center; line-height: 1.9em; }
   </style>
   <script type="text/javascript">
   // <![CDATA[
   var LCprogressTxt='---';
   
   function LCupdateProgress(percent,progresstext,id) {
      LCprogressTxt=progresstext;
      \$('#progressbar'+id).progressbar('value',percent);
   }
   // ]]>
   </script>
   ENDPROGRESSUPDATE
   }
   
   my $LClastpercent;
   my $LCidcnt;
   my $LCcurrentid;
   
   sub LCprogressbar {
       my ($r)=(@_);
       $LClastpercent=0;
       $LCidcnt++;
       $LCcurrentid=$$.'_'.$LCidcnt;
       my $starting=&mt('Starting');
       my $content=(<<ENDPROGBAR);
   <p>
     <div id="progressbar$LCcurrentid">
       <span class="pblabel">$starting</span>
     </div>
   </p>
   ENDPROGBAR
       &r_print($r,$content.&LCprogressbar_script($LCcurrentid));
   }
   
   sub LCprogressbarUpdate {
       my ($r,$val,$text)=@_;
       unless ($val) { 
          if ($LClastpercent) {
              $val=$LClastpercent;
          } else {
              $val=0;
          }
       }
       if ($val<0) { $val=0; }
       if ($val>100) { $val=0; }
       $LClastpercent=$val;
       unless ($text) { $text=$val.'%'; }
       $text=&js_ready($text);
       &r_print($r,<<ENDUPDATE);
   <script type="text/javascript">
   // <![CDATA[
   LCupdateProgress($val,'$text','$LCcurrentid');
   // ]]>
   </script>
   ENDUPDATE
   }
   
   sub LCprogressbarClose {
       my ($r)=@_;
       $LClastpercent=0;
       &r_print($r,<<ENDCLOSE);
   <script type="text/javascript">
   // <![CDATA[
   \$("#progressbar$LCcurrentid").hide('slow'); 
   // ]]>
   </script>
   ENDCLOSE
   }
   
   sub r_print {
       my ($r,$to_print)=@_;
       if ($r) {
         $r->print($to_print);
         $r->rflush();
       } else {
         print($to_print);
       }
   }
   
 sub html_encode {  sub html_encode {
     my ($result) = @_;      my ($result) = @_;
   
Line 6997  sub html_encode { Line 7842  sub html_encode {
           
     return $result;      return $result;
 }  }
   
 sub js_ready {  sub js_ready {
     my ($result) = @_;      my ($result) = @_;
   
Line 7033  sub validate_page { Line 7879  sub validate_page {
     }      }
 }  }
   
   
   sub start_scrollbox {
       my ($outerwidth,$width,$height,$id,$bgcolor)=@_;
       unless ($outerwidth) { $outerwidth='520px'; }
       unless ($width) { $width='500px'; }
       unless ($height) { $height='200px'; }
       my ($table_id,$div_id,$tdcol);
       if ($id ne '') {
           $table_id = " id='table_$id'";
           $div_id = " id='div_$id'";
       }
       if ($bgcolor ne '') {
           $tdcol = "background-color: $bgcolor;";
       }
       return <<"END";
   <table style="width: $outerwidth; border: 1px solid none;"$table_id><tr><td style="width: $width;$tdcol"><div style="overflow:auto; width:$width; height: $height;"$div_id>
   END
   }
   
   sub end_scrollbox {
       return '</div></td></tr></table>';
   }
   
 sub simple_error_page {  sub simple_error_page {
     my ($r,$title,$msg) = @_;      my ($r,$title,$msg) = @_;
     my $page =      my $page =
  &Apache::loncommon::start_page($title).   &Apache::loncommon::start_page($title).
  &mt($msg).   '<p class="LC_error">'.&mt($msg).'</p>'.
  &Apache::loncommon::end_page();   &Apache::loncommon::end_page();
     if (ref($r)) {      if (ref($r)) {
  $r->print($page);   $r->print($page);
Line 7060  sub simple_error_page { Line 7929  sub simple_error_page {
     }      }
   
     sub start_data_table {      sub start_data_table {
  my ($add_class) = @_;   my ($add_class,$id) = @_;
  my $css_class = (join(' ','LC_data_table',$add_class));   my $css_class = (join(' ','LC_data_table',$add_class));
         &start_data_table_count();          my $table_id;
  return '<table class="'.$css_class.'">'."\n";          if (defined($id)) {
               $table_id = ' id="'.$id.'"';
           }
    &start_data_table_count();
    return '<table class="'.$css_class.'"'.$table_id.'>'."\n";
     }      }
   
     sub end_data_table {      sub end_data_table {
         &end_data_table_count();   &end_data_table_count();
  return '</table>'."\n";;   return '</table>'."\n";;
     }      }
   
     sub start_data_table_row {      sub start_data_table_row {
  my ($add_class) = @_;   my ($add_class, $id) = @_;
  $row_count[0]++;   $row_count[0]++;
  my $css_class = ($row_count[0] % 2)?'LC_odd_row':'LC_even_row';   my $css_class = ($row_count[0] % 2)?'LC_odd_row':'LC_even_row';
  $css_class = (join(' ',$css_class,$add_class)) unless ($add_class eq '');   $css_class = (join(' ',$css_class,$add_class)) unless ($add_class eq '');
  return  '<tr class="'.$css_class.'">'."\n";;          $id = (' id="'.$id.'"') unless ($id eq '');
           return  '<tr class="'.$css_class.'"'.$id.'>'."\n";
     }      }
           
     sub continue_data_table_row {      sub continue_data_table_row {
  my ($add_class) = @_;   my ($add_class, $id) = @_;
  my $css_class = ($row_count[0] % 2)?'LC_odd_row':'LC_even_row';   my $css_class = ($row_count[0] % 2)?'LC_odd_row':'LC_even_row';
  $css_class = (join(' ',$css_class,$add_class)) unless ($add_class eq '');;   $css_class = (join(' ',$css_class,$add_class)) unless ($add_class eq '');
  return  '<tr class="'.$css_class.'">'."\n";;          $id = (' id="'.$id.'"') unless ($id eq '');
           return  '<tr class="'.$css_class.'"'.$id.'>'."\n";
     }      }
   
     sub end_data_table_row {      sub end_data_table_row {
Line 7188  sub get_users_function { Line 8063  sub get_users_function {
         $function='admin';          $function='admin';
     }      }
     if (($env{'request.role'}=~/^(au|ca|aa)/) ||      if (($env{'request.role'}=~/^(au|ca|aa)/) ||
         ($ENV{'REQUEST_URI'}=~/^(\/priv|\~)/)) {          ($ENV{'REQUEST_URI'}=~ m{/^(/priv)})) {
         $function='author';          $function='author';
     }      }
     return $function;      return $function;
Line 7246  role status: active, previous or future. Line 8121  role status: active, previous or future.
   
 sub check_user_status {  sub check_user_status {
     my ($udom,$uname,$cdom,$crs,$role,$sec) = @_;      my ($udom,$uname,$cdom,$crs,$role,$sec) = @_;
     my $extra = &Apache::lonnet::freeze_escape({'skipcheck' => 1});      my %userinfo = &Apache::lonnet::dump('roles',$udom,$uname);
     my %userinfo = &Apache::lonnet::dump('roles',$udom,$uname,'.',undef,$extra);  
     my @uroles = keys %userinfo;      my @uroles = keys %userinfo;
     my $srchstr;      my $srchstr;
     my $active_chk = 'none';      my $active_chk = 'none';
Line 7923  sub user_picker { Line 8797  sub user_picker {
     my ($newuserscript,$new_user_create);      my ($newuserscript,$new_user_create);
     my $context_dom = $env{'request.role.domain'};      my $context_dom = $env{'request.role.domain'};
     if ($context eq 'requestcrs') {      if ($context eq 'requestcrs') {
         if ($env{'form.coursedom'} ne '') {          if ($env{'form.coursedom'} ne '') { 
             $context_dom = $env{'form.coursedom'};              $context_dom = $env{'form.coursedom'};
         }          }
     }      }
Line 8149  sub user_rule_formats { Line 9023  sub user_rule_formats {
     my ($rules,$ruleorder) = &Apache::lonnet::inst_userrules($domain,$check);      my ($rules,$ruleorder) = &Apache::lonnet::inst_userrules($domain,$check);
     if ((ref($rules) eq 'HASH') && (ref($ruleorder) eq 'ARRAY')) {      if ((ref($rules) eq 'HASH') && (ref($ruleorder) eq 'ARRAY')) {
         if (@{$ruleorder} > 0) {          if (@{$ruleorder} > 0) {
             $output = '<br />'.&mt("$text{$check} with the following format(s) may <span class=\"LC_cusr_emph\">only</span> be used for verified users at [_1]:",$domdesc).' <ul>';              $output = '<br />'.
                         &mt($text{$check}.' with the following format(s) may [_1]only[_2] be used for verified users at [_3]:',
                             '<span class="LC_cusr_emph">','</span>',$domdesc).
                         ' <ul>';
             foreach my $rule (@{$ruleorder}) {              foreach my $rule (@{$ruleorder}) {
                 if (ref($curr_rules) eq 'ARRAY') {                  if (ref($curr_rules) eq 'ARRAY') {
                     if (grep(/^\Q$rule\E$/,@{$curr_rules})) {                      if (grep(/^\Q$rule\E$/,@{$curr_rules})) {
Line 8303  sub get_standard_codeitems { Line 9180  sub get_standard_codeitems {
   
 =item * sorted_slots()  =item * sorted_slots()
   
 Sorts an array of slot names in order of slot start time (earliest first).   Sorts an array of slot names in order of an optional sort key,
   default sort is by slot start time (earliest first). 
   
 Inputs:  Inputs:
   
Line 8313  slotsarr  - Reference to array of unsort Line 9191  slotsarr  - Reference to array of unsort
   
 slots     - Reference to hash of hash, where outer hash keys are slot names.  slots     - Reference to hash of hash, where outer hash keys are slot names.
   
   sortkey   - Name of key in inner hash to be sorted on (e.g., starttime).
   
 =back  =back
   
 Returns:  Returns:
   
 =over 4  =over 4
   
 sorted   - An array of slot names sorted by the start time of the slot.  sorted   - An array of slot names sorted by a specified sort key 
              (default sort key is start time of the slot).
 =back  
   
 =back  =back
   
Line 8329  sorted   - An array of slot names sorted Line 9208  sorted   - An array of slot names sorted
   
   
 sub sorted_slots {  sub sorted_slots {
     my ($slotsarr,$slots) = @_;      my ($slotsarr,$slots,$sortkey) = @_;
       if ($sortkey eq '') {
           $sortkey = 'starttime';
       }
     my @sorted;      my @sorted;
     if ((ref($slotsarr) eq 'ARRAY') && (ref($slots) eq 'HASH')) {      if ((ref($slotsarr) eq 'ARRAY') && (ref($slots) eq 'HASH')) {
         @sorted =          @sorted =
             sort {              sort {
                      if (ref($slots->{$a}) && ref($slots->{$b})) {                       if (ref($slots->{$a}) && ref($slots->{$b})) {
                          return $slots->{$a}{'starttime'} <=> $slots->{$b}{'starttime'}                           return $slots->{$a}{$sortkey} <=> $slots->{$b}{$sortkey}
                      }                       }
                      if (ref($slots->{$a})) { return -1;}                       if (ref($slots->{$a})) { return -1;}
                      if (ref($slots->{$b})) { return 1;}                       if (ref($slots->{$b})) { return 1;}
Line 8345  sub sorted_slots { Line 9227  sub sorted_slots {
     return @sorted;      return @sorted;
 }  }
   
   =pod
   
   =item * get_future_slots()
   
   Inputs:
   
   =over 4
   
   cnum - course number
   
   cdom - course domain
   
   now - current UNIX time
   
   symb - optional symb
   
   =back
   
   Returns:
   
   =over 4
   
   sorted_reservable - ref to array of student_schedulable slots currently 
                       reservable, ordered by end date of reservation period.
   
   reservable_now - ref to hash of student_schedulable slots currently
                    reservable.
   
       Keys in inner hash are:
       (a) symb: either blank or symb to which slot use is restricted.
       (b) endreserve: end date of reservation period. 
   
   sorted_future - ref to array of student_schedulable slots reservable in
                   the future, ordered by start date of reservation period.
   
   future_reservable - ref to hash of student_schedulable slots reservable
                       in the future.
   
       Keys in inner hash are:
       (a) symb: either blank or symb to which slot use is restricted.
       (b) startreserve:  start date of reservation period.
   
   =back
   
   =cut
   
   sub get_future_slots {
       my ($cnum,$cdom,$now,$symb) = @_;
       my (%reservable_now,%future_reservable,@sorted_reservable,@sorted_future);
       my %slots = &Apache::lonnet::get_course_slots($cnum,$cdom);
       foreach my $slot (keys(%slots)) {
           next unless($slots{$slot}->{'type'} eq 'schedulable_student');
           if ($symb) {
               next if (($slots{$slot}->{'symb'} ne '') && 
                        ($slots{$slot}->{'symb'} ne $symb));
           }
           if (($slots{$slot}->{'starttime'} > $now) &&
               ($slots{$slot}->{'endtime'} > $now)) {
               if (($slots{$slot}->{'allowedsections'}) || ($slots{$slot}->{'allowedusers'})) {
                   my $userallowed = 0;
                   if ($slots{$slot}->{'allowedsections'}) {
                       my @allowed_sec = split(',',$slots{$slot}->{'allowedsections'});
                       if (!defined($env{'request.role.sec'})
                           && grep(/^No section assigned$/,@allowed_sec)) {
                           $userallowed=1;
                       } else {
                           if (grep(/^\Q$env{'request.role.sec'}\E$/,@allowed_sec)) {
                               $userallowed=1;
                           }
                       }
                       unless ($userallowed) {
                           if (defined($env{'request.course.groups'})) {
                               my @groups = split(/:/,$env{'request.course.groups'});
                               foreach my $group (@groups) {
                                   if (grep(/^\Q$group\E$/,@allowed_sec)) {
                                       $userallowed=1;
                                       last;
                                   }
                               }
                           }
                       }
                   }
                   if ($slots{$slot}->{'allowedusers'}) {
                       my @allowed_users = split(',',$slots{$slot}->{'allowedusers'});
                       my $user = $env{'user.name'}.':'.$env{'user.domain'};
                       if (grep(/^\Q$user\E$/,@allowed_users)) {
                           $userallowed = 1;
                       }
                   }
                   next unless($userallowed);
               }
               my $startreserve = $slots{$slot}->{'startreserve'};
               my $endreserve = $slots{$slot}->{'endreserve'};
               my $symb = $slots{$slot}->{'symb'};
               if (($startreserve < $now) &&
                   (!$endreserve || $endreserve > $now)) {
                   my $lastres = $endreserve;
                   if (!$lastres) {
                       $lastres = $slots{$slot}->{'starttime'};
                   }
                   $reservable_now{$slot} = {
                                              symb       => $symb,
                                              endreserve => $lastres
                                            };
               } elsif (($startreserve > $now) &&
                        (!$endreserve || $endreserve > $startreserve)) {
                   $future_reservable{$slot} = {
                                                 symb         => $symb,
                                                 startreserve => $startreserve
                                               };
               }
           }
       }
       my @unsorted_reservable = keys(%reservable_now);
       if (@unsorted_reservable > 0) {
           @sorted_reservable = 
               &sorted_slots(\@unsorted_reservable,\%reservable_now,'endreserve');
       }
       my @unsorted_future = keys(%future_reservable);
       if (@unsorted_future > 0) {
           @sorted_future =
               &sorted_slots(\@unsorted_future,\%future_reservable,'startreserve');
       }
       return (\@sorted_reservable,\%reservable_now,\@sorted_future,\%future_reservable);
   }
   
 =pod  =pod
   
   =back
   
 =head1 HTTP Helpers  =head1 HTTP Helpers
   
 =over 4  =over 4
Line 8486  sub get_env_multiple { Line 9495  sub get_env_multiple {
   
 sub ask_for_embedded_content {  sub ask_for_embedded_content {
     my ($actionurl,$state,$allfiles,$codebase,$args)=@_;      my ($actionurl,$state,$allfiles,$codebase,$args)=@_;
     my (%subdependencies,%dependencies,%mapping,%existing,%newfiles,%pathchanges);      my (%subdependencies,%dependencies,%mapping,%existing,%newfiles,%pathchanges,
     my $num = 0;          %currsubfile,%unused,$rem);
       my $counter = 0;
       my $numnew = 0;
     my $numremref = 0;      my $numremref = 0;
     my $numinvalid = 0;      my $numinvalid = 0;
     my $numpathchg = 0;      my $numpathchg = 0;
     my $numexisting = 0;      my $numexisting = 0;
     my ($output,$upload_output,$toplevel,$url,$udom,$uname,$getpropath);      my $numunused = 0;
       my ($output,$upload_output,$toplevel,$url,$udom,$uname,$getpropath,$cdom,$cnum,
           $fileloc,$filename,$delete_output,$modify_output,$title,$symb,$path);
       my $heading = &mt('Upload embedded files');
       my $buttontext = &mt('Upload');
   
       my $navmap;
       if ($env{'request.course.id'}) {
           $navmap = Apache::lonnavmaps::navmap->new();
       }
     if (($actionurl eq '/adm/portfolio') || ($actionurl eq '/adm/coursegrp_portfolio')) {      if (($actionurl eq '/adm/portfolio') || ($actionurl eq '/adm/coursegrp_portfolio')) {
         my $current_path='/';          my $current_path='/';
         if ($env{'form.currentpath'}) {          if ($env{'form.currentpath'}) {
Line 8511  sub ask_for_embedded_content { Line 9531  sub ask_for_embedded_content {
         $url .= $current_path;          $url .= $current_path;
         $getpropath = 1;          $getpropath = 1;
     } elsif (($actionurl eq '/adm/upload') || ($actionurl eq '/adm/testbank') ||      } elsif (($actionurl eq '/adm/upload') || ($actionurl eq '/adm/testbank') ||
              ($actionurl eq '/adm/imsimport')) {               ($actionurl eq '/adm/imsimport')) { 
         ($uname,my $rest) = ($args->{'current_path'} =~ m{/priv/($match_username)/?(.*)$});          my ($udom,$uname,$rest) = ($args->{'current_path'} =~ m{/priv/($match_domain)/($match_username)/?(.*)$});
         $url = '/home/'.$uname.'/public_html/';          $url = $Apache::lonnet::perlvar{'lonDocRoot'}."/priv/$udom/$uname/";
         $toplevel = $url;          $toplevel = $url;
         if ($rest ne '') {          if ($rest ne '') {
             $url .= $rest;              $url .= $rest;
         }          }
     } elsif ($actionurl eq '/adm/coursedocs') {      } elsif ($actionurl eq '/adm/coursedocs') {
         if (ref($args) eq 'HASH') {          if (ref($args) eq 'HASH') {
            $url = $args->{'docs_url'};              $url = $args->{'docs_url'};
            $toplevel = $url;              $toplevel = $url;
               if ($args->{'context'} eq 'paste') {
                   ($cdom,$cnum) = ($url =~ m{^\Q/uploaded/\E($match_domain)/($match_courseid)/});
                   ($path) = 
                       ($toplevel =~ m{^(\Q/uploaded/$cdom/$cnum/\E(?:docs|supplemental)/(?:default|\d+)/\d+)/});
                   $fileloc = &Apache::lonnet::filelocation('',$toplevel);
                   $fileloc =~ s{^/}{};
               }
           }
       } elsif ($actionurl eq '/adm/dependencies')  {
           if ($env{'request.course.id'} ne '') {
               $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
               $cnum =  $env{'course.'.$env{'request.course.id'}.'.num'};
               if (ref($args) eq 'HASH') {
                   $url = $args->{'docs_url'};
                   $title = $args->{'docs_title'};
                   $toplevel = "/$url";
                   ($rem) = ($toplevel =~ m{^(.+/)[^/]+$});
                   ($path) =  
                       ($toplevel =~ m{^(\Q/uploaded/$cdom/$cnum/\E(?:docs|supplemental)/(?:default|\d+)/\d+)/});
                   $fileloc = &Apache::lonnet::filelocation('',$toplevel);
                   $fileloc =~ s{^/}{};
                   ($filename) = ($fileloc =~ m{.+/([^/]+)$});
                   $heading = &mt('Status of dependencies in [_1]',"$title ($filename)");
               }
         }          }
     }      }
     my $now = time();      my $now = time();
Line 8560  sub ask_for_embedded_content { Line 9604  sub ask_for_embedded_content {
             }              }
         }          }
     }      }
       my $dirptr = 16384;
     foreach my $path (keys(%subdependencies)) {      foreach my $path (keys(%subdependencies)) {
         my %currsubfile;          $currsubfile{$path} = {};
         if (($actionurl eq '/adm/portfolio') || ($actionurl eq '/adm/coursegrp_portfolio')) {          if (($actionurl eq '/adm/portfolio') || ($actionurl eq '/adm/coursegrp_portfolio')) { 
             my @subdir_list = &Apache::lonnet::dirlist($url.$path,$udom,$uname,$getpropath);              my ($sublistref,$listerror) =
             foreach my $line (@subdir_list) {                  &Apache::lonnet::dirlist($url.$path,$udom,$uname,$getpropath);
                 my ($file_name,$rest) = split(/\&/,$line,2);              if (ref($sublistref) eq 'ARRAY') {
                 $currsubfile{$file_name} = 1;                  foreach my $line (@{$sublistref}) {
                       my ($file_name,$rest) = split(/\&/,$line,2);
                       $currsubfile{$path}{$file_name} = 1;
                   }
             }              }
         } elsif (($actionurl eq '/adm/upload') || ($actionurl eq '/adm/testbank')) {          } elsif (($actionurl eq '/adm/upload') || ($actionurl eq '/adm/testbank')) {
             if (opendir(my $dir,$url.'/'.$path)) {              if (opendir(my $dir,$url.'/'.$path)) {
                 my @subdir_list = grep(!/^\./,readdir($dir));                  my @subdir_list = grep(!/^\./,readdir($dir));
                 map {$currsubfile{$_} = 1;} @subdir_list;                  map {$currsubfile{$path}{$_} = 1;} @subdir_list;
               }
           } elsif (($actionurl eq '/adm/dependencies') ||
                    (($actionurl eq '/adm/coursedocs') && (ref($args) eq 'HASH') &&
                     ($args->{'context'} eq 'paste'))) {
               if ($env{'request.course.id'} ne '') {
                   my ($dir) = ($fileloc =~ m{^(.+/)[^/]+$});
                   if ($dir ne '') {
                       my ($sublistref,$listerror) =
                           &Apache::lonnet::dirlist($dir.$path,$cdom,$cnum,$getpropath,undef,'/');
                       if (ref($sublistref) eq 'ARRAY') {
                           foreach my $line (@{$sublistref}) {
                               my ($file_name,$dom,undef,$testdir,undef,undef,undef,undef,$size,
                                   undef,$mtime)=split(/\&/,$line,12);
                               unless (($testdir&$dirptr) ||
                                       ($file_name =~ /^\.\.?$/)) {
                                   $currsubfile{$path}{$file_name} = [$size,$mtime];
                               }
                           }
                       }
                   }
             }              }
         }          }
         foreach my $file (keys(%{$subdependencies{$path}})) {          foreach my $file (keys(%{$subdependencies{$path}})) {
             if ($currsubfile{$file}) {              if (exists($currsubfile{$path}{$file})) {
                 my $item = $path.'/'.$file;                  my $item = $path.'/'.$file;
                 unless ($mapping{$item} eq $item) {                  unless ($mapping{$item} eq $item) {
                     $pathchanges{$item} = 1;                      $pathchanges{$item} = 1;
Line 8586  sub ask_for_embedded_content { Line 9654  sub ask_for_embedded_content {
                 $newfiles{$path.'/'.$file} = 1;                  $newfiles{$path.'/'.$file} = 1;
             }              }
         }          }
           if ($actionurl eq '/adm/dependencies') {
               foreach my $path (keys(%currsubfile)) {
                   if (ref($currsubfile{$path}) eq 'HASH') {
                       foreach my $file (keys(%{$currsubfile{$path}})) {
                            unless ($subdependencies{$path}{$file}) {
                                next if (($rem ne '') &&
                                         (($env{"httpref.$rem"."$path/$file"} ne '') ||
                                          (ref($navmap) &&
                                          (($navmap->getResourceByUrl($rem."$path/$file") ne '') ||
                                           (($file =~ /^(.*\.s?html?)\.bak$/i) &&
                                            ($navmap->getResourceByUrl($rem."$path/$1")))))));
                                $unused{$path.'/'.$file} = 1; 
                            }
                       }
                   }
               }
           }
     }      }
     my %currfile;      my %currfile;
     if (($actionurl eq '/adm/portfolio') || ($actionurl eq '/adm/coursegrp_portfolio')) {      if (($actionurl eq '/adm/portfolio') || ($actionurl eq '/adm/coursegrp_portfolio')) {
         my @dir_list = &Apache::lonnet::dirlist($url,$udom,$uname,$getpropath);          my ($dirlistref,$listerror) =
         foreach my $line (@dir_list) {              &Apache::lonnet::dirlist($url,$udom,$uname,$getpropath);
             my ($file_name,$rest) = split(/\&/,$line,2);          if (ref($dirlistref) eq 'ARRAY') {
             $currfile{$file_name} = 1;              foreach my $line (@{$dirlistref}) {
                   my ($file_name,$rest) = split(/\&/,$line,2);
                   $currfile{$file_name} = 1;
               }
         }          }
     } elsif (($actionurl eq '/adm/upload') || ($actionurl eq '/adm/testbank')) {      } elsif (($actionurl eq '/adm/upload') || ($actionurl eq '/adm/testbank')) {
         if (opendir(my $dir,$url)) {          if (opendir(my $dir,$url)) {
             my @dir_list = grep(!/^\./,readdir($dir));              my @dir_list = grep(!/^\./,readdir($dir));
             map {$currfile{$_} = 1;} @dir_list;              map {$currfile{$_} = 1;} @dir_list;
         }          }
       } elsif (($actionurl eq '/adm/dependencies') ||
                (($actionurl eq '/adm/coursedocs') && (ref($args) eq 'HASH') &&
                 ($args->{'context'} eq 'paste'))) {
           if ($env{'request.course.id'} ne '') {
               my ($dir) = ($fileloc =~ m{^(.+/)[^/]+$});
               if ($dir ne '') {
                   my ($dirlistref,$listerror) =
                       &Apache::lonnet::dirlist($dir,$cdom,$cnum,$getpropath,undef,'/');
                   if (ref($dirlistref) eq 'ARRAY') {
                       foreach my $line (@{$dirlistref}) {
                           my ($file_name,$dom,undef,$testdir,undef,undef,undef,undef,
                               $size,undef,$mtime)=split(/\&/,$line,12);
                           unless (($testdir&$dirptr) ||
                                   ($file_name =~ /^\.\.?$/)) {
                               $currfile{$file_name} = [$size,$mtime];
                           }
                       }
                   }
               }
           }
     }      }
     foreach my $file (keys(%dependencies)) {      foreach my $file (keys(%dependencies)) {
         if ($currfile{$file}) {          if (exists($currfile{$file})) {
             unless ($mapping{$file} eq $file) {              unless ($mapping{$file} eq $file) {
                 $pathchanges{$file} = 1;                  $pathchanges{$file} = 1;
             }              }
Line 8611  sub ask_for_embedded_content { Line 9719  sub ask_for_embedded_content {
             $newfiles{$file} = 1;              $newfiles{$file} = 1;
         }          }
     }      }
       foreach my $file (keys(%currfile)) {
           unless (($file eq $filename) ||
                   ($file eq $filename.'.bak') ||
                   ($dependencies{$file})) {
               if ($actionurl eq '/adm/dependencies') {
                   next if (($rem ne '') &&
                            (($env{"httpref.$rem".$file} ne '') ||
                             (ref($navmap) &&
                             (($navmap->getResourceByUrl($rem.$file) ne '') ||
                              (($file =~ /^(.*\.s?html?)\.bak$/i) &&
                               ($navmap->getResourceByUrl($rem.$1)))))));
               }
               $unused{$file} = 1;
           }
       }
       if (($actionurl eq '/adm/coursedocs') && (ref($args) eq 'HASH') &&
           ($args->{'context'} eq 'paste')) {
           $counter = scalar(keys(%existing));
           $numpathchg = scalar(keys(%pathchanges));
           return ($output,$counter,$numpathchg,\%existing); 
       }
     foreach my $embed_file (sort {lc($a) cmp lc($b)} keys(%newfiles)) {      foreach my $embed_file (sort {lc($a) cmp lc($b)} keys(%newfiles)) {
           if ($actionurl eq '/adm/dependencies') {
               next if ($embed_file =~ m{^\w+://});
           }
         $upload_output .= &start_data_table_row().          $upload_output .= &start_data_table_row().
                           '<td><span class="LC_filename">'.$embed_file.'</span>';                            '<td><img src="'.&icon($embed_file).'" />&nbsp;'.
                             '<span class="LC_filename">'.$embed_file.'</span>';
         unless ($mapping{$embed_file} eq $embed_file) {          unless ($mapping{$embed_file} eq $embed_file) {
             $upload_output .= '<br /><span class="LC_info" style="font-size:smaller;">'.&mt('changed from: [_1]',$mapping{$embed_file}).'</span>';              $upload_output .= '<br /><span class="LC_info" style="font-size:smaller;">'.&mt('changed from: [_1]',$mapping{$embed_file}).'</span>';
         }          }
         $upload_output .= '</td><td>';          $upload_output .= '</td><td>';
         if ($args->{'ignore_remote_references'}          if ($args->{'ignore_remote_references'} && $embed_file =~ m{^\w+://}) { 
             && $embed_file =~ m{^\w+://}) {  
             $upload_output.='<span class="LC_warning">'.&mt("URL points to other server.").'</span>';              $upload_output.='<span class="LC_warning">'.&mt("URL points to other server.").'</span>';
             $numremref++;              $numremref++;
         } elsif ($args->{'error_on_invalid_names'}          } elsif ($args->{'error_on_invalid_names'}
             && $embed_file ne &Apache::lonnet::clean_filename($embed_file,{'keep_path' => 1,})) {              && $embed_file ne &Apache::lonnet::clean_filename($embed_file,{'keep_path' => 1,})) {
   
             $upload_output.='<span class="LC_warning">'.&mt('Invalid characters').'</span>';              $upload_output.='<span class="LC_warning">'.&mt('Invalid characters').'</span>';
             $numinvalid++;              $numinvalid++;
         } else {          } else {
             $upload_output .= &embedded_file_element('upload_embedded',$num,              $upload_output .= &embedded_file_element('upload_embedded',$counter,
                                                      $embed_file,\%mapping,                                                       $embed_file,\%mapping,
                                                      $allfiles,$codebase);                                                       $allfiles,$codebase,'upload');
             $num++;              $counter ++;
               $numnew ++;
         }          }
         $upload_output .= '</td>'.&Apache::loncommon::end_data_table_row()."\n";          $upload_output .= '</td>'.&Apache::loncommon::end_data_table_row()."\n";
     }      }
     foreach my $embed_file (sort {lc($a) cmp lc($b)} keys(%existing)) {      foreach my $embed_file (sort {lc($a) cmp lc($b)} keys(%existing)) {
         $upload_output .= &start_data_table_row().          if ($actionurl eq '/adm/dependencies') {
                           '<td><span class="LC_filename">'.$embed_file.'</span></td>'.              my ($size,$mtime) = &get_dependency_details(\%currfile,\%currsubfile,$embed_file);
                           '<td><span class="LC_warning">'.&mt('Already exists').'</span></td>'.              $modify_output .= &start_data_table_row().
                           &Apache::loncommon::end_data_table_row()."\n";                                '<td><a href="'.$path.'/'.$embed_file.'" style="text-decoration:none;">'.
                                 '<img src="'.&icon($embed_file).'" border="0" />'.
                                 '&nbsp;<span class="LC_filename">'.$embed_file.'</span></a></td>'.
                                 '<td>'.$size.'</td>'.
                                 '<td>'.$mtime.'</td>'.
                                 '<td><label><input type="checkbox" name="mod_upload_dep" '.
                                 'onclick="toggleBrowse('."'$counter'".')" id="mod_upload_dep_'.
                                 $counter.'" value="'.$counter.'" />'.&mt('Yes').'</label>'.
                                 '<div id="moduploaddep_'.$counter.'" style="display:none;">'.
                                 &embedded_file_element('upload_embedded',$counter,
                                                        $embed_file,\%mapping,
                                                        $allfiles,$codebase,'modify').
                                 '</div></td>'.
                                 &end_data_table_row()."\n";
               $counter ++;
           } else {
               $upload_output .= &start_data_table_row().
                                 '<td><span class="LC_filename">'.$embed_file.'</span></td>';
                                 '<td><span class="LC_warning">'.&mt('Already exists').'</span></td>'.
                                 &Apache::loncommon::end_data_table_row()."\n";
           }
       }
       my $delidx = $counter;
       foreach my $oldfile (sort {lc($a) cmp lc($b)} keys(%unused)) {
           my ($size,$mtime) = &get_dependency_details(\%currfile,\%currsubfile,$oldfile);
           $delete_output .= &start_data_table_row().
                             '<td><img src="'.&icon($oldfile).'" />'.
                             '&nbsp;<span class="LC_filename">'.$oldfile.'</span></td>'.
                             '<td>'.$size.'</td>'.
                             '<td>'.$mtime.'</td>'.
                             '<td><label><input type="checkbox" name="del_upload_dep" '.
                             ' value="'.$delidx.'" />'.&mt('Yes').'</label>'.
                             &embedded_file_element('upload_embedded',$delidx,
                                                    $oldfile,\%mapping,$allfiles,
                                                    $codebase,'delete').'</td>'.
                             &end_data_table_row()."\n"; 
           $numunused ++;
           $delidx ++;
     }      }
     if ($upload_output) {      if ($upload_output) {
         $upload_output = &start_data_table().          $upload_output = &start_data_table().
                          $upload_output.                           $upload_output.
                          &end_data_table()."\n";                           &end_data_table()."\n";
     }      }
       if ($modify_output) {
           $modify_output = &start_data_table().
                            &start_data_table_header_row().
                            '<th>'.&mt('File').'</th>'.
                            '<th>'.&mt('Size (KB)').'</th>'.
                            '<th>'.&mt('Modified').'</th>'.
                            '<th>'.&mt('Upload replacement?').'</th>'.
                            &end_data_table_header_row().
                            $modify_output.
                            &end_data_table()."\n";
       }
       if ($delete_output) {
           $delete_output = &start_data_table().
                            &start_data_table_header_row().
                            '<th>'.&mt('File').'</th>'.
                            '<th>'.&mt('Size (KB)').'</th>'.
                            '<th>'.&mt('Modified').'</th>'.
                            '<th>'.&mt('Delete?').'</th>'.
                            &end_data_table_header_row().
                            $delete_output.
                            &end_data_table()."\n";
       }
     my $applies = 0;      my $applies = 0;
     if ($numremref) {      if ($numremref) {
         $applies ++;          $applies ++;
Line 8656  sub ask_for_embedded_content { Line 9847  sub ask_for_embedded_content {
     if ($numexisting) {      if ($numexisting) {
         $applies ++;          $applies ++;
     }      }
     if ($num) {      if ($counter || $numunused) {
         $output = '<form name="upload_embedded" action="'.$actionurl.'"'.          $output = '<form name="upload_embedded" action="'.$actionurl.'"'.
                   ' method="post" enctype="multipart/form-data">'."\n".                    ' method="post" enctype="multipart/form-data">'."\n".
                   $state.                    $state.'<h3>'.$heading.'</h3>'; 
                   '<h3>'.&mt('Upload embedded files').          if ($actionurl eq '/adm/dependencies') {
                   ':</h3>'.$upload_output.'<br />'."\n".              if ($numnew) {
                   '<input type ="hidden" name="number_embedded_items" value="'.                  $output .= '<h4>'.&mt('Missing dependencies').'</h4>'.
                   $num.'" />'."\n";                             '<p>'.&mt('The following files need to be uploaded.').'</p>'."\n".
         if ($actionurl eq '') {                             $upload_output.'<br />'."\n";
               }
               if ($numexisting) {
                   $output .= '<h4>'.&mt('Uploaded dependencies (in use)').'</h4>'.
                              '<p>'.&mt('Upload a new file to replace the one currently in use.').'</p>'."\n".
                              $modify_output.'<br />'."\n";
                              $buttontext = &mt('Save changes');
               }
               if ($numunused) {
                   $output .= '<h4>'.&mt('Unused files').'</h4>'.
                              '<p>'.&mt('The following uploaded files are no longer used.').'</p>'."\n".
                              $delete_output.'<br />'."\n";
                              $buttontext = &mt('Save changes');
               }
           } else {
               $output .= $upload_output.'<br />'."\n";
           }
           $output .= '<input type ="hidden" name="number_embedded_items" value="'.
                      $counter.'" />'."\n";
           if ($actionurl eq '/adm/dependencies') { 
               $output .= '<input type ="hidden" name="number_newemb_items" value="'.
                          $numnew.'" />'."\n";
           } elsif ($actionurl eq '') {
             $output .=  '<input type="hidden" name="phase" value="three" />';              $output .=  '<input type="hidden" name="phase" value="three" />';
         }          }
     } elsif ($applies) {      } elsif ($applies) {
         $output = '<b>'.&mt('Referenced files').'</b>:<br />';          $output = '<b>'.&mt('Referenced files').'</b>:<br />';
         if ($applies > 1) {          if ($applies > 1) {
             $output .=              $output .=  
                 &mt('No files need to be uploaded, as one of the following applies to each reference:').'<ul>';                  &mt('No files need to be uploaded, as one of the following applies to each reference:').'<ul>';
             if ($numremref) {              if ($numremref) {
                 $output .= '<li>'.&mt('reference is to a URL which points to another server').'</li>'."\n";                  $output .= '<li>'.&mt('reference is to a URL which points to another server').'</li>'."\n";
Line 8692  sub ask_for_embedded_content { Line 9905  sub ask_for_embedded_content {
         $output .= $upload_output.'<br />';          $output .= $upload_output.'<br />';
     }      }
     my ($pathchange_output,$chgcount);      my ($pathchange_output,$chgcount);
     $chgcount = $num;      $chgcount = $counter;
     if (keys(%pathchanges) > 0) {      if (keys(%pathchanges) > 0) {
         foreach my $embed_file (sort {lc($a) cmp lc($b)} keys(%pathchanges)) {          foreach my $embed_file (sort {lc($a) cmp lc($b)} keys(%pathchanges)) {
             if ($num) {              if ($counter) {
                 $output .= &embedded_file_element('pathchange',$chgcount,                  $output .= &embedded_file_element('pathchange',$chgcount,
                                                   $embed_file,\%mapping,                                                    $embed_file,\%mapping,
                                                   $allfiles,$codebase);                                                    $allfiles,$codebase,'change');
             } else {              } else {
                 $pathchange_output .=                  $pathchange_output .= 
                     &start_data_table_row().                      &start_data_table_row().
                     '<td><input type ="checkbox" name="namechange" value="'.                      '<td><input type ="checkbox" name="namechange" value="'.
                     $chgcount.'" checked="checked" /></td>'.                      $chgcount.'" checked="checked" /></td>'.
                     '<td>'.$mapping{$embed_file}.'</td>'.                      '<td>'.$mapping{$embed_file}.'</td>'.
                     '<td>'.$embed_file.                      '<td>'.$embed_file.
                     &embedded_file_element('pathchange',$numpathchg,$embed_file,                      &embedded_file_element('pathchange',$numpathchg,$embed_file,
                                            \%mapping,$allfiles,$codebase).                                             \%mapping,$allfiles,$codebase,'change').
                     '</td>'.&end_data_table_row();                      '</td>'.&end_data_table_row();
             }              }
             $numpathchg ++;              $numpathchg ++;
             $chgcount ++;              $chgcount ++;
         }          }
     }      }
     if ($num) {      if ($counter) {
         if ($numpathchg) {          if ($numpathchg) {
             $output .= '<input type ="hidden" name="number_pathchange_items" value="'.              $output .= '<input type ="hidden" name="number_pathchange_items" value="'.
                        $numpathchg.'" />'."\n";                         $numpathchg.'" />'."\n";
         }          }
         if (($actionurl eq '/adm/upload') || ($actionurl eq '/adm/testbank') ||          if (($actionurl eq '/adm/upload') || ($actionurl eq '/adm/testbank') || 
             ($actionurl eq '/adm/imsimport')) {              ($actionurl eq '/adm/imsimport')) {
             $output .= '<input type="hidden" name="phase" value="three" />'."\n";              $output .= '<input type="hidden" name="phase" value="three" />'."\n";
         } elsif ($actionurl eq '/adm/portfolio' || $actionurl eq '/adm/coursegrp_portfolio') {          } elsif ($actionurl eq '/adm/portfolio' || $actionurl eq '/adm/coursegrp_portfolio') {
             $output .= '<input type="hidden" name="action" value="upload_embedded" />';              $output .= '<input type="hidden" name="action" value="upload_embedded" />';
           } elsif ($actionurl eq '/adm/dependencies') {
               $output .= '<input type="hidden" name="action" value="process_changes" />';
         }          }
         $output .=  '<input type ="submit" value="'.&mt('Upload Listed Files').'" />'."\n".          $output .=  '<input type ="submit" value="'.$buttontext.'" />'."\n".'</form>'."\n";
                     &mt('(only files for which a location has been provided will be uploaded)').'</form>'."\n";  
     } elsif ($numpathchg) {      } elsif ($numpathchg) {
         my %pathchange = ();          my %pathchange = ();
         $output .= &modify_html_form('pathchange',$actionurl,$state,\%pathchange,$pathchange_output);          $output .= &modify_html_form('pathchange',$actionurl,$state,\%pathchange,$pathchange_output);
         if (($actionurl eq '/adm/portfolio') || ($actionurl eq '/adm/coursegrp_portfolio')) {          if (($actionurl eq '/adm/portfolio') || ($actionurl eq '/adm/coursegrp_portfolio')) {
             $output .= '<p>'.&mt('or').'</p>';              $output .= '<p>'.&mt('or').'</p>'; 
         }          } 
     }      }
     return ($output,$num,$numpathchg);      return ($output,$counter,$numpathchg);
 }  }
   
 sub embedded_file_element {  sub embedded_file_element {
     my ($context,$num,$embed_file,$mapping,$allfiles,$codebase) = @_;      my ($context,$num,$embed_file,$mapping,$allfiles,$codebase,$type) = @_;
     return unless ((ref($mapping) eq 'HASH') && (ref($allfiles) eq 'HASH') &&      return unless ((ref($mapping) eq 'HASH') && (ref($allfiles) eq 'HASH') &&
                    (ref($codebase) eq 'HASH'));                     (ref($codebase) eq 'HASH'));
     my $output;      my $output;
     if ($context eq 'upload_embedded') {      if (($context eq 'upload_embedded') && ($type ne 'delete')) {
        $output = '<input name="embedded_item_'.$num.'" type="file" value="" />'."\n";         $output = '<input name="embedded_item_'.$num.'" type="file" value="" />'."\n";
     }      }
     $output .= '<input name="embedded_orig_'.$num.'" type="hidden" value="'.      $output .= '<input name="embedded_orig_'.$num.'" type="hidden" value="'.
                &escape($embed_file).'" />';                 &escape($embed_file).'" />';
     unless (($context eq 'upload_embedded') &&      unless (($context eq 'upload_embedded') && 
             ($mapping->{$embed_file} eq $embed_file)) {              ($mapping->{$embed_file} eq $embed_file)) {
         $output .='          $output .='
         <input name="embedded_ref_'.$num.'" type="hidden" value="'.&escape($mapping->{$embed_file}).'" />';          <input name="embedded_ref_'.$num.'" type="hidden" value="'.&escape($mapping->{$embed_file}).'" />';
Line 8769  sub embedded_file_element { Line 9983  sub embedded_file_element {
     return $output;      return $output;
 }  }
   
   sub get_dependency_details {
       my ($currfile,$currsubfile,$embed_file) = @_;
       my ($size,$mtime,$showsize,$showmtime);
       if ((ref($currfile) eq 'HASH') && (ref($currsubfile))) {
           if ($embed_file =~ m{/}) {
               my ($path,$fname) = split(/\//,$embed_file);
               if (ref($currsubfile->{$path}{$fname}) eq 'ARRAY') {
                   ($size,$mtime) = @{$currsubfile->{$path}{$fname}};
               }
           } else {
               if (ref($currfile->{$embed_file}) eq 'ARRAY') {
                   ($size,$mtime) = @{$currfile->{$embed_file}};
               }
           }
           $showsize = $size/1024.0;
           $showsize = sprintf("%.1f",$showsize);
           if ($mtime > 0) {
               $showmtime = &Apache::lonlocal::locallocaltime($mtime);
           }
       }
       return ($showsize,$showmtime);
   }
   
   sub ask_embedded_js {
       return <<"END";
   <script type="text/javascript"">
   // <![CDATA[
   function toggleBrowse(counter) {
       var chkboxid = document.getElementById('mod_upload_dep_'+counter);
       var fileid = document.getElementById('embedded_item_'+counter);
       var uploaddivid = document.getElementById('moduploaddep_'+counter);
       if (chkboxid.checked == true) {
           uploaddivid.style.display='block';
       } else {
           uploaddivid.style.display='none';
           fileid.value = '';
       }
   }
   // ]]>
   </script>
   
   END
   }
   
 sub upload_embedded {  sub upload_embedded {
     my ($context,$dirpath,$uname,$udom,$dir_root,$url_root,$group,$disk_quota,      my ($context,$dirpath,$uname,$udom,$dir_root,$url_root,$group,$disk_quota,
         $current_disk_usage,$hiddenstate,$actionurl) = @_;          $current_disk_usage,$hiddenstate,$actionurl) = @_;
Line 8827  sub upload_embedded { Line 10085  sub upload_embedded {
             $output .= &mt('File name not allowed - rename the file to remove the number immediately before the file extension([_1]) and re-upload.',$2).'<br />';              $output .= &mt('File name not allowed - rename the file to remove the number immediately before the file extension([_1]) and re-upload.',$2).'<br />';
             next;              next;
         }          }
   
         $env{'form.embedded_item_'.$i.'.filename'}=$fname;          $env{'form.embedded_item_'.$i.'.filename'}=$fname;
         if ($context eq 'portfolio') {          if ($context eq 'portfolio') {
             my $result;              my $result;
Line 8848  sub upload_embedded { Line 10105  sub upload_embedded {
                     next;                      next;
                 } else {                  } else {
                     $output .= &mt('Uploaded [_1]','<span class="LC_filename">'.                      $output .= &mt('Uploaded [_1]','<span class="LC_filename">'.
                                $path.$fname.'</span>').'<br />';                                  $path.$fname.'</span>').'<br />';     
                 }                  }
             }              }
         } elsif ($context eq 'coursedoc') {          } elsif ($context eq 'coursedoc') {
Line 8871  sub upload_embedded { Line 10128  sub upload_embedded {
             my $fullpath = $dir_root.$dirpath.'/'.$path;              my $fullpath = $dir_root.$dirpath.'/'.$path;
             my $dest = $fullpath.$fname;              my $dest = $fullpath.$fname;
             my $url = $url_root.$dirpath.'/'.$path.$fname;              my $url = $url_root.$dirpath.'/'.$path.$fname;
             my @parts=split(/\//,$fullpath);              my @parts=split(/\//,"$dirpath/$path");
             my $count;              my $count;
             my $filepath = $dir_root;              my $filepath = $dir_root;
             for ($count=4;$count<=$#parts;$count++) {              foreach my $subdir (@parts) {
                 $filepath .= "/$parts[$count]";                  $filepath .= "/$subdir";
                 if ((-e $filepath)!=1) {                  if (!-e $filepath) {
                     mkdir($filepath,0770);                      mkdir($filepath,0770);
                 }                  }
             }              }
Line 8884  sub upload_embedded { Line 10141  sub upload_embedded {
             if (!open($fh,'>'.$dest)) {              if (!open($fh,'>'.$dest)) {
                 &Apache::lonnet::logthis('Failed to create '.$dest);                  &Apache::lonnet::logthis('Failed to create '.$dest);
                 $output .= '<span class="LC_error">'.                  $output .= '<span class="LC_error">'.
                            &mt('An error occurred while trying to upload [_1] for embedded element [_2].',$orig_uploaded_filename,$env{'form.embedded_orig_'.$i}).                             &mt('An error occurred while trying to upload [_1] for embedded element [_2].',
                                  $orig_uploaded_filename,$env{'form.embedded_orig_'.$i}).
                            '</span><br />';                             '</span><br />';
             } else {              } else {
                 if (!print $fh $env{'form.embedded_item_'.$i}) {                  if (!print $fh $env{'form.embedded_item_'.$i}) {
                     &Apache::lonnet::logthis('Failed to write to '.$dest);                      &Apache::lonnet::logthis('Failed to write to '.$dest);
                     $output .= '<span class="LC_error">'.                      $output .= '<span class="LC_error">'.
                               &mt('An error occurred while writing the file [_1] for embedded element [_2].',$orig_uploaded_filename,$env{'form.embedded_orig_'.$i}).                                &mt('An error occurred while writing the file [_1] for embedded element [_2].',
                                     $orig_uploaded_filename,$env{'form.embedded_orig_'.$i}).
                               '</span><br />';                                '</span><br />';
                 } else {                  } else {
                     $output .= &mt('Uploaded [_1]','<span class="LC_filename">'.                      $output .= &mt('Uploaded [_1]','<span class="LC_filename">'.
Line 8912  sub upload_embedded { Line 10171  sub upload_embedded {
     }      }
     $output .= &modify_html_form('upload_embedded',$actionurl,$hiddenstate,\%pathchange);      $output .= &modify_html_form('upload_embedded',$actionurl,$hiddenstate,\%pathchange);
     $returnflag = 'ok';      $returnflag = 'ok';
     if (keys(%pathchange) > 0) {      my $numpathchgs = scalar(keys(%pathchange));
       if ($numpathchgs > 0) {
         if ($context eq 'portfolio') {          if ($context eq 'portfolio') {
             $output .= '<p>'.&mt('or').'</p>';              $output .= '<p>'.&mt('or').'</p>';
         } elsif ($context eq 'testbank') {          } elsif ($context eq 'testbank') {
             $output .=  '<p>'.&mt('Or [_1]continue[_2] the testbank import without modifying the reference(s).','<a href="javascript:document.testbankForm.submit();">','</a>').'</p>';              $output .=  '<p>'.&mt('Or [_1]continue[_2] the testbank import without modifying the reference(s).',
                                     '<a href="javascript:document.testbankForm.submit();">','</a>').'</p>';
             $returnflag = 'modify_orightml';              $returnflag = 'modify_orightml';
         }          }
     }      }
     return ($output.$footer,$returnflag);      return ($output.$footer,$returnflag,$numpathchgs);
 }  }
   
 sub modify_html_form {  sub modify_html_form {
Line 8966  sub modify_html_form { Line 10227  sub modify_html_form {
         }          }
     }      }
     if ($modifyform) {      if ($modifyform) {
           if ($actionurl eq '/adm/dependencies') {
               $hiddenstate .= '<input type="hidden" name="action" value="modifyhrefs" />';
           }
         return '<h3>'.&mt('Changes in content of HTML file required').'</h3>'."\n".          return '<h3>'.&mt('Changes in content of HTML file required').'</h3>'."\n".
                '<p>'.&mt('Changes need to be made to the reference(s) used for one or more of the dependencies, if your HTML file is to work correctly:').'<ol>'."\n".                 '<p>'.&mt('Changes need to be made to the reference(s) used for one or more of the dependencies, if your HTML file is to work correctly:').'<ol>'."\n".
                '<li>'.&mt('For consistency between the reference(s) and the location of the corresponding stored file within LON-CAPA.').'</li>'."\n".                 '<li>'.&mt('For consistency between the reference(s) and the location of the corresponding stored file within LON-CAPA.').'</li>'."\n".
Line 8994  sub modify_html_refs { Line 10258  sub modify_html_refs {
         $container = $env{'form.container'};          $container = $env{'form.container'};
     } elsif ($context eq 'coursedoc') {      } elsif ($context eq 'coursedoc') {
         $container = $env{'form.primaryurl'};          $container = $env{'form.primaryurl'};
       } elsif ($context eq 'manage_dependencies') {
           (undef,undef,$container) = &Apache::lonnet::decode_symb($env{'form.symb'});
           $container = "/$container";
     } else {      } else {
         $container = $env{'form.filename'};          $container = $Apache::lonnet::perlvar{'lonDocRoot'}.$env{'form.filename'};
         $container =~ s{^/priv/(\Q$uname\E)/(.*)}{/home/$1/public_html/$2};  
     }      }
     my (%allfiles,%codebase,$output,$content);      my (%allfiles,%codebase,$output,$content);
     my @changes = &get_env_multiple('form.namechange');      my @changes = &get_env_multiple('form.namechange');
     return unless (@changes > 0);      unless (@changes > 0) {
     if (($context eq 'portfolio') || ($context eq 'coursedoc')) {          if (wantarray) {
         return unless ($container =~ m{^/uploaded/\Q$udom\E/\Q$uname\E/});              return ('',0,0); 
           } else {
               return;
           }
       }
       if (($context eq 'portfolio') || ($context eq 'coursedoc') || 
           ($context eq 'manage_dependencies')) {
           unless ($container =~ m{^/uploaded/\Q$udom\E/\Q$uname\E/}) {
               if (wantarray) {
                   return ('',0,0);
               } else {
                   return;
               }
           } 
         $content = &Apache::lonnet::getfile($container);          $content = &Apache::lonnet::getfile($container);
         return if ($content eq '-1');          if ($content eq '-1') {
               if (wantarray) {
                   return ('',0,0);
               } else {
                   return;
               }
           }
     } else {      } else {
         return unless ($container =~ /^\Q$dir_root\E/);          unless ($container =~ /^\Q$dir_root\E/) {
               if (wantarray) {
                   return ('',0,0);
               } else {
                   return;
               }
           } 
         if (open(my $fh,"<$container")) {          if (open(my $fh,"<$container")) {
             $content = join('', <$fh>);              $content = join('', <$fh>);
             close($fh);              close($fh);
         } else {          } else {
             return;              if (wantarray) {
                   return ('',0,0);
               } else {
                   return;
               }
         }          }
     }      }
     my ($count,$codebasecount) = (0,0);      my ($count,$codebasecount) = (0,0);
     my $mm = new File::MMagic;      my $mm = new File::MMagic;
     my $mime_type = $mm->checktype_contents($content);      my $mime_type = $mm->checktype_contents($content);
     if ($mime_type eq 'text/html') {      if ($mime_type eq 'text/html') {
         my $parse_result =          my $parse_result = 
             &Apache::lonnet::extract_embedded_items($container,\%allfiles,              &Apache::lonnet::extract_embedded_items($container,\%allfiles,
                                                     \%codebase,\$content);                                                      \%codebase,\$content);
         if ($parse_result eq 'ok') {          if ($parse_result eq 'ok') {
Line 9028  sub modify_html_refs { Line 10323  sub modify_html_refs {
                 if ($allfiles{$ref}) {                  if ($allfiles{$ref}) {
                     my $newname =  $orig;                      my $newname =  $orig;
                     my ($attrib_regexp,$codebase);                      my ($attrib_regexp,$codebase);
                     my $attrib_regexp = &unescape($env{'form.embedded_attrib_'.$i});                      $attrib_regexp = &unescape($env{'form.embedded_attrib_'.$i});
                     if ($attrib_regexp =~ /:/) {                      if ($attrib_regexp =~ /:/) {
                         $attrib_regexp =~ s/\:/|/g;                          $attrib_regexp =~ s/\:/|/g;
                     }                      }
Line 9037  sub modify_html_refs { Line 10332  sub modify_html_refs {
                         $count += $numchg;                          $count += $numchg;
                     }                      }
                     if ($env{'form.embedded_codebase_'.$i} ne '') {                      if ($env{'form.embedded_codebase_'.$i} ne '') {
                         my $codebase = &unescape($env{'form.embedded_codebase_'.$i});                          $codebase = &unescape($env{'form.embedded_codebase_'.$i});
                         my $numchg = ($content =~ s/(codebase\s*=\s*["']?)\Q$codebase\E(["']?)/$1.$2/i); #' stupid emacs                          my $numchg = ($content =~ s/(codebase\s*=\s*["']?)\Q$codebase\E(["']?)/$1.$2/i); #' stupid emacs
                         $codebasecount ++;                          $codebasecount ++;
                     }                      }
Line 9045  sub modify_html_refs { Line 10340  sub modify_html_refs {
             }              }
             if ($count || $codebasecount) {              if ($count || $codebasecount) {
                 my $saveresult;                  my $saveresult;
                 if ($context eq 'portfolio' || $context eq 'coursedoc') {                  if (($context eq 'portfolio') || ($context eq 'coursedoc') || 
                       ($context eq 'manage_dependencies')) {
                     my $url = &Apache::lonnet::store_edited_file($container,$content,$udom,$uname,\$saveresult);                      my $url = &Apache::lonnet::store_edited_file($container,$content,$udom,$uname,\$saveresult);
                     if ($url eq $container) {                      if ($url eq $container) {
                         my ($fname) = ($container =~ m{/([^/]+)$});                          my ($fname) = ($container =~ m{/([^/]+)$});
Line 9078  sub modify_html_refs { Line 10374  sub modify_html_refs {
                      ' to modify references: '.$parse_result);                       ' to modify references: '.$parse_result);
         }          }
     }      }
     return $output;      if (wantarray) {
           return ($output,$count,$codebasecount);
       } else {
           return $output;
       }
 }  }
   
 sub check_for_existing {  sub check_for_existing {
Line 9103  sub check_for_upload { Line 10403  sub check_for_upload {
     my $filesize = length($env{'form.'.$element});      my $filesize = length($env{'form.'.$element});
     if (!$filesize) {      if (!$filesize) {
         my $msg = '<span class="LC_error">'.          my $msg = '<span class="LC_error">'.
                   &mt('Unable to upload [_1]. (size = [_2] bytes)',                    &mt('Unable to upload [_1]. (size = [_2] bytes)', 
                       '<span class="LC_filename">'.$fname.'</span>',                        '<span class="LC_filename">'.$fname.'</span>',
                       $filesize).'<br />'.                        $filesize).'<br />'.
                   &mt('Either the file you attempted to upload was empty, or your web browser was unable to read its contents.').'<br />';                    &mt('Either the file you attempted to upload was empty, or your web browser was unable to read its contents.').'<br />'.
                   '</span>';                    '</span>';
         return ('zero_bytes',$msg);          return ('zero_bytes',$msg);
     }      }
     $filesize =  $filesize/1000; #express in k (1024?)      $filesize =  $filesize/1000; #express in k (1024?)
     my $getpropath = 1;      my $getpropath = 1;
     my @dir_list = &Apache::lonnet::dirlist($portfolio_root.$path,$udom,$uname,      my ($dirlistref,$listerror) =
                                             $getpropath);           &Apache::lonnet::dirlist($portfolio_root.$path,$udom,$uname,$getpropath);
     my $found_file = 0;      my $found_file = 0;
     my $locked_file = 0;      my $locked_file = 0;
     my @lockers;      my @lockers;
Line 9121  sub check_for_upload { Line 10421  sub check_for_upload {
     if ($env{'request.course.id'}) {      if ($env{'request.course.id'}) {
         $navmap = Apache::lonnavmaps::navmap->new();          $navmap = Apache::lonnavmaps::navmap->new();
     }      }
     foreach my $line (@dir_list) {      if (ref($dirlistref) eq 'ARRAY') {
         my ($file_name,$rest)=split(/\&/,$line,2);          foreach my $line (@{$dirlistref}) {
         if ($file_name eq $fname){              my ($file_name,$rest)=split(/\&/,$line,2);
             $file_name = $path.$file_name;              if ($file_name eq $fname){
             if ($group ne '') {                  $file_name = $path.$file_name;
                 $file_name = $group.$file_name;                  if ($group ne '') {
             }                      $file_name = $group.$file_name;
             $found_file = 1;                  }
             if (&Apache::lonnet::is_locked($file_name,$udom,$uname,\@lockers) eq 'true') {                  $found_file = 1;
                 foreach my $lock (@lockers) {                  if (&Apache::lonnet::is_locked($file_name,$udom,$uname,\@lockers) eq 'true') {
                     if (ref($lock) eq 'ARRAY') {                      foreach my $lock (@lockers) {
                         my ($symb,$crsid) = @{$lock};                          if (ref($lock) eq 'ARRAY') {
                         if ($crsid eq $env{'request.course.id'}) {                              my ($symb,$crsid) = @{$lock};
                             if (ref($navmap)) {                              if ($crsid eq $env{'request.course.id'}) {
                                 my $res = $navmap->getBySymb($symb);                                  if (ref($navmap)) {
                                 foreach my $part (@{$res->parts()}) {                                      my $res = $navmap->getBySymb($symb);
                                     my ($slot_status,$slot_time,$slot_name)=$res->check_for_slot($part);                                      foreach my $part (@{$res->parts()}) { 
                                     unless (($slot_status == $res->RESERVED) ||                                          my ($slot_status,$slot_time,$slot_name)=$res->check_for_slot($part);
                                             ($slot_status == $res->RESERVED_LOCATION)) {                                          unless (($slot_status == $res->RESERVED) ||
                                         $locked_file = 1;                                                  ($slot_status == $res->RESERVED_LOCATION)) {
                                               $locked_file = 1;
                                           }
                                     }                                      }
                                   } else {
                                       $locked_file = 1;
                                 }                                  }
                             } else {                              } else {
                                 $locked_file = 1;                                  $locked_file = 1;
                             }                              }
                         } else {  
                             $locked_file = 1;  
                         }                          }
                     }                     }
                 }                  } else {
             } else {                      my @info = split(/\&/,$rest);
                 my @info = split(/\&/,$rest);                      my $currsize = $info[6]/1000;
                 my $currsize = $info[6]/1000;                      if ($currsize < $filesize) {
                 if ($currsize < $filesize) {                          my $extra = $filesize - $currsize;
                     my $extra = $filesize - $currsize;                          if (($current_disk_usage + $extra) > $disk_quota) {
                     if (($current_disk_usage + $extra) > $disk_quota) {                              my $msg = '<span class="LC_error">'.
                         my $msg = '<span class="LC_error">'.                                        &mt('Unable to upload [_1]. (size = [_2] kilobytes). Disk quota will be exceeded if existing (smaller) file with same name (size = [_3] kilobytes) is replaced.',
                                   &mt('Unable to upload [_1]. (size = [_2] kilobytes). Disk quota will be exceeded if existing (smaller) file with same name (size = [_3] kilobytes) is replaced.',                                            '<span class="LC_filename">'.$fname.'</span>',$filesize,$currsize).'</span>'.
                                       '<span class="LC_filename">'.$fname.'</span>',$filesize,$currsize).'</span>'.                                        '<br />'.&mt('Disk quota is [_1] kilobytes. Your current disk usage is [_2] kilobytes.',
                                   '<br />'.&mt('Disk quota is [_1] kilobytes. Your current disk usage is [_2] kilobytes.',                                                     $disk_quota,$current_disk_usage);
                                                $disk_quota,$current_disk_usage);                              return ('will_exceed_quota',$msg);
                         return ('will_exceed_quota',$msg);                          }
                     }                      }
                 }                  }
             }              }
Line 9232  sub check_for_traversal { Line 10534  sub check_for_traversal {
     return $cleanpath;      return $cleanpath;
 }  }
   
   sub is_archive_file {
       my ($mimetype) = @_;
       if (($mimetype eq 'application/octet-stream') ||
           ($mimetype eq 'application/x-stuffit') ||
           ($mimetype =~ m{^application/(x\-)?(compressed|tar|zip|tgz|gz|gtar|gzip|gunzip|bz|bz2|bzip2)})) {
           return 1;
       }
       return;
   }
   
   sub decompress_form {
       my ($mimetype,$archiveurl,$action,$noextract,$hiddenelements,$dirlist) = @_;
       my %lt = &Apache::lonlocal::texthash (
           this => 'This file is an archive file.',
           camt => 'This file is a Camtasia archive file.',
           itsc => 'Its contents are as follows:',
           youm => 'You may wish to extract its contents.',
           extr => 'Extract contents',
           auto => 'LON-CAPA can process the files automatically, or you can decide how each should be handled.',
           proa => 'Process automatically?',
           yes  => 'Yes',
           no   => 'No',
           fold => 'Title for folder containing movie',
           movi => 'Title for page containing embedded movie', 
       );
       my $fileloc = &Apache::lonnet::filelocation(undef,$archiveurl);
       my ($is_camtasia,$topdir,%toplevel,@paths);
       my $info = &list_archive_contents($fileloc,\@paths);
       if (@paths) {
           foreach my $path (@paths) {
               $path =~ s{^/}{};
               if ($path =~ m{^([^/]+)/$}) {
                   $topdir = $1;
               }
               if ($path =~ m{^([^/]+)/}) {
                   $toplevel{$1} = $path;
               } else {
                   $toplevel{$path} = $path;
               }
           }
       }
       if ($mimetype =~ m{^application/(x\-)?(compressed|zip)}) {
           my @camtasia = ("$topdir/","$topdir/index.html",
                           "$topdir/media/",
                           "$topdir/media/$topdir.mp4",
                           "$topdir/media/FirstFrame.png",
                           "$topdir/media/player.swf",
                           "$topdir/media/swfobject.js",
                           "$topdir/media/expressInstall.swf");
           my @diffs = &compare_arrays(\@paths,\@camtasia);
           if (@diffs == 0) {
               $is_camtasia = 1;
           }
       }
       my $output;
       if ($is_camtasia) {
           $output = <<"ENDCAM";
   <script type="text/javascript" language="Javascript">
   // <![CDATA[
   
   function camtasiaToggle() {
       for (var i=0; i<document.uploaded_decompress.autoextract_camtasia.length; i++) {
           if (document.uploaded_decompress.autoextract_camtasia[i].checked) {
               if (document.uploaded_decompress.autoextract_camtasia[i].value == 1) {
   
                   document.getElementById('camtasia_titles').style.display='block';
               } else {
                   document.getElementById('camtasia_titles').style.display='none';
               }
           }
       }
       return;
   }
   
   // ]]>
   </script>
   <p>$lt{'camt'}</p>
   ENDCAM
       } else {
           $output = '<p>'.$lt{'this'};
           if ($info eq '') {
               $output .= ' '.$lt{'youm'}.'</p>'."\n";
           } else {
               $output .= ' '.$lt{'itsc'}.'</p>'."\n".
                          '<div><pre>'.$info.'</pre></div>';
           }
       }
       $output .= '<form name="uploaded_decompress" action="'.$action.'" method="post">'."\n";
       my $duplicates;
       my $num = 0;
       if (ref($dirlist) eq 'ARRAY') {
           foreach my $item (@{$dirlist}) {
               if (ref($item) eq 'ARRAY') {
                   if (exists($toplevel{$item->[0]})) {
                       $duplicates .= 
                           &start_data_table_row().
                           '<td><label><input type="radio" name="archive_overwrite_'.$num.'" '.
                           'value="0" checked="checked" />'.&mt('No').'</label>'.
                           '&nbsp;<label><input type="radio" name="archive_overwrite_'.$num.'" '.
                           'value="1" />'.&mt('Yes').'</label>'.
                           '<input type="hidden" name="archive_overwrite_name_'.$num.'" value="'.$item->[0].'" /></td>'."\n".
                           '<td>'.$item->[0].'</td>';
                       if ($item->[2]) {
                           $duplicates .= '<td>'.&mt('Directory').'</td>';
                       } else {
                           $duplicates .= '<td>'.&mt('File').'</td>';
                       }
                       $duplicates .= '<td>'.$item->[3].'</td>'.
                                      '<td>'.
                                      &Apache::lonlocal::locallocaltime($item->[4]).
                                      '</td>'.
                                      &end_data_table_row();
                       $num ++;
                   }
               }
           }
       }
       my $itemcount;
       if (@paths > 0) {
           $itemcount = scalar(@paths);
       } else {
           $itemcount = 1;
       }
       if ($is_camtasia) {
           $output .= $lt{'auto'}.'<br />'.
                      '<span class="LC_nobreak">'.$lt{'proa'}.'<label>'.
                      '<input type="radio" name="autoextract_camtasia" value="1" onclick="javascript:camtasiaToggle();" checked="checked" />'.
                      $lt{'yes'}.'</label>&nbsp;<label>'.
                      '<input type="radio" name="autoextract_camtasia" value="0" onclick="javascript:camtasiaToggle();" />'.
                      $lt{'no'}.'</label></span><br />'.
                      '<div id="camtasia_titles" style="display:block">'.
                      &Apache::lonhtmlcommon::start_pick_box().
                      &Apache::lonhtmlcommon::row_title($lt{'fold'}).
                      '<input type="textbox" name="camtasia_foldername" value="'.$env{'form.comment'}.'" />'."\n".
                      &Apache::lonhtmlcommon::row_closure().
                      &Apache::lonhtmlcommon::row_title($lt{'movi'}).
                      '<input type="textbox" name="camtasia_moviename" value="" />'."\n".
                      &Apache::lonhtmlcommon::row_closure(1).
                      &Apache::lonhtmlcommon::end_pick_box().
                      '</div>';
       }
       $output .= 
           '<input type="hidden" name="archive_overwrite_total" value="'.$num.'" />'.
           '<input type="hidden" name="archive_itemcount" value="'.$itemcount.'" />'.
           "\n";
       if ($duplicates ne '') {
           $output .= '<p><span class="LC_warning">'.
                      &mt('Warning: decompression of the archive will overwrite the following items which already exist:').'</span><br />'.  
                      &start_data_table().
                      &start_data_table_header_row().
                      '<th>'.&mt('Overwrite?').'</th>'.
                      '<th>'.&mt('Name').'</th>'.
                      '<th>'.&mt('Type').'</th>'.
                      '<th>'.&mt('Size').'</th>'.
                      '<th>'.&mt('Last modified').'</th>'.
                      &end_data_table_header_row().
                      $duplicates.
                      &end_data_table().
                      '</p>';
       }
       $output .= '<input type="hidden" name="archiveurl" value="'.$archiveurl.'" />'."\n";
       if (ref($hiddenelements) eq 'HASH') {
           foreach my $hidden (sort(keys(%{$hiddenelements}))) {
               $output .= '<input type="hidden" name="'.$hidden.'" value="'.$hiddenelements->{$hidden}.'" />'."\n";
           }
       }
       $output .= <<"END";
   <br />
   <input type="submit" name="decompress" value="$lt{'extr'}" />
   </form>
   $noextract
   END
       return $output;
   }
   
   sub decompression_utility {
       my ($program) = @_;
       my @utilities = ('tar','gunzip','bunzip2','unzip'); 
       my $location;
       if (grep(/^\Q$program\E$/,@utilities)) { 
           foreach my $dir ('/bin/','/usr/bin/','/usr/local/bin/','/sbin/',
                            '/usr/sbin/') {
               if (-x $dir.$program) {
                   $location = $dir.$program;
                   last;
               }
           }
       }
       return $location;
   }
   
   sub list_archive_contents {
       my ($file,$pathsref) = @_;
       my (@cmd,$output);
       my $needsregexp;
       if ($file =~ /\.zip$/) {
           @cmd = (&decompression_utility('unzip'),"-l");
           $needsregexp = 1;
       } elsif (($file =~ m/\.tar\.gz$/) ||
                ($file =~ /\.tgz$/)) {
           @cmd = (&decompression_utility('tar'),"-ztf");
       } elsif ($file =~ /\.tar\.bz2$/) {
           @cmd = (&decompression_utility('tar'),"-jtf");
       } elsif ($file =~ m|\.tar$|) {
           @cmd = (&decompression_utility('tar'),"-tf");
       }
       if (@cmd) {
           undef($!);
           undef($@);
           if (open(my $fh,"-|", @cmd, $file)) {
               while (my $line = <$fh>) {
                   $output .= $line;
                   chomp($line);
                   my $item;
                   if ($needsregexp) {
                       ($item) = ($line =~ /^\s*\d+\s+[\d\-]+\s+[\d:]+\s*(.+)$/); 
                   } else {
                       $item = $line;
                   }
                   if ($item ne '') {
                       unless (grep(/^\Q$item\E$/,@{$pathsref})) {
                           push(@{$pathsref},$item);
                       } 
                   }
               }
               close($fh);
           }
       }
       return $output;
   }
   
   sub decompress_uploaded_file {
       my ($file,$dir) = @_;
       &Apache::lonnet::appenv({'cgi.file' => $file});
       &Apache::lonnet::appenv({'cgi.dir' => $dir});
       my $result = &Apache::lonnet::ssi_body('/cgi-bin/decompress.pl');
       my ($handle) = ($env{'user.environment'} =~m{/([^/]+)\.id$});
       my $lonidsdir = $Apache::lonnet::perlvar{'lonIDsDir'};
       &Apache::lonnet::transfer_profile_to_env($lonidsdir,$handle,1);
       my $decompressed = $env{'cgi.decompressed'};
       &Apache::lonnet::delenv('cgi.file');
       &Apache::lonnet::delenv('cgi.dir');
       &Apache::lonnet::delenv('cgi.decompressed');
       return ($decompressed,$result);
   }
   
   sub process_decompression {
       my ($docudom,$docuname,$file,$destination,$dir_root,$hiddenelem) = @_;
       my ($dir,$error,$warning,$output);
       if ($file !~ /\.(zip|tar|bz2|gz|tar.gz|tar.bz2|tgz)$/) {
           $error = &mt('File name not a supported archive file type.').
                    '<br />'.&mt('File name should end with one of: [_1].',
                                 '.zip, .tar, .bz2, .gz, .tar.gz, .tar.bz2, .tgz');
       } else {
           my $docuhome = &Apache::lonnet::homeserver($docuname,$docudom);
           if ($docuhome eq 'no_host') {
               $error = &mt('Could not determine home server for course.');
           } else {
               my @ids=&Apache::lonnet::current_machine_ids();
               my $currdir = "$dir_root/$destination";
               if (grep(/^\Q$docuhome\E$/,@ids)) {
                   $dir = &LONCAPA::propath($docudom,$docuname).
                          "$dir_root/$destination";
               } else {
                   $dir = $Apache::lonnet::perlvar{'lonDocRoot'}.
                          "$dir_root/$docudom/$docuname/$destination";
                   unless (&Apache::lonnet::repcopy_userfile("$dir/$file") eq 'ok') {
                       $error = &mt('Archive file not found.');
                   }
               }
               my (@to_overwrite,@to_skip);
               if ($env{'form.archive_overwrite_total'} > 0) {
                   my $total = $env{'form.archive_overwrite_total'};
                   for (my $i=0; $i<$total; $i++) {
                       if ($env{'form.archive_overwrite_'.$i} == 1) {
                           push(@to_overwrite,$env{'form.archive_overwrite_name_'.$i});
                       } elsif ($env{'form.archive_overwrite_'.$i} == 0) {
                           push(@to_skip,$env{'form.archive_overwrite_name_'.$i});
                       }
                   }
               }
               my $numskip = scalar(@to_skip);
               if (($numskip > 0) && 
                   ($numskip == $env{'form.archive_itemcount'})) {
                   $warning = &mt('All items in the archive file already exist, and no overwriting of existing files has been requested.');         
               } elsif ($dir eq '') {
                   $error = &mt('Directory containing archive file unavailable.');
               } elsif (!$error) {
                   my ($decompressed,$display);
                   if ($numskip > 0) {
                       my $tempdir = time.'_'.$$.int(rand(10000));
                       mkdir("$dir/$tempdir",0755);
                       system("mv $dir/$file $dir/$tempdir/$file");
                       ($decompressed,$display) = 
                           &decompress_uploaded_file($file,"$dir/$tempdir");
                       foreach my $item (@to_skip) {
                           if (($item ne '') && ($item !~ /\.\./)) {
                               if (-f "$dir/$tempdir/$item") { 
                                   unlink("$dir/$tempdir/$item");
                               } elsif (-d "$dir/$tempdir/$item") {
                                   system("rm -rf $dir/$tempdir/$item");
                               }
                           }
                       }
                       system("mv $dir/$tempdir/* $dir");
                       rmdir("$dir/$tempdir");   
                   } else {
                       ($decompressed,$display) = 
                           &decompress_uploaded_file($file,$dir);
                   }
                   if ($decompressed eq 'ok') {
                       $output = '<p class="LC_info">'.
                                 &mt('Files extracted successfully from archive.').
                                 '</p>'."\n";
                       my ($warning,$result,@contents);
                       my ($newdirlistref,$newlisterror) =
                           &Apache::lonnet::dirlist($currdir,$docudom,
                                                    $docuname,1);
                       my (%is_dir,%changes,@newitems);
                       my $dirptr = 16384;
                       if (ref($newdirlistref) eq 'ARRAY') {
                           foreach my $dir_line (@{$newdirlistref}) {
                               my ($item,undef,undef,$testdir)=split(/\&/,$dir_line,5);
                               unless (($item =~ /^\.+$/) || ($item eq $file) || 
                                       ((@to_skip > 0) && (grep(/^\Q$item\E$/,@to_skip)))) {
                                   push(@newitems,$item);
                                   if ($dirptr&$testdir) {
                                       $is_dir{$item} = 1;
                                   }
                                   $changes{$item} = 1;
                               }
                           }
                       }
                       if (keys(%changes) > 0) {
                           foreach my $item (sort(@newitems)) {
                               if ($changes{$item}) {
                                   push(@contents,$item);
                               }
                           }
                       }
                       if (@contents > 0) {
                           my $wantform;
                           unless ($env{'form.autoextract_camtasia'}) {
                               $wantform = 1;
                           }
                           my (%children,%parent,%dirorder,%titles);
                           my ($count,$datatable) = &get_extracted($docudom,$docuname,
                                                                   $currdir,\%is_dir,
                                                                   \%children,\%parent,
                                                                   \@contents,\%dirorder,
                                                                   \%titles,$wantform);
                           if ($datatable ne '') {
                               $output .= &archive_options_form('decompressed',$datatable,
                                                                $count,$hiddenelem);
                               my $startcount = 6;
                               $output .= &archive_javascript($startcount,$count,
                                                              \%titles,\%children);
                           }
                           if ($env{'form.autoextract_camtasia'}) {
                               my %displayed;
                               my $total = 1;
                               $env{'form.archive_directory'} = [];
                               foreach my $i (sort { $a <=> $b } keys(%dirorder)) {
                                   my $path = join('/',map { $titles{$_}; } @{$dirorder{$i}});
                                   $path =~ s{/$}{};
                                   my $item;
                                   if ($path ne '') {
                                       $item = "$path/$titles{$i}";
                                   } else {
                                       $item = $titles{$i};
                                   }
                                   $env{'form.archive_content_'.$i} = "$dir_root/$destination/$item";
                                   if ($item eq $contents[0]) {
                                       push(@{$env{'form.archive_directory'}},$i);
                                       $env{'form.archive_'.$i} = 'display';
                                       $env{'form.archive_title_'.$i} = $env{'form.camtasia_foldername'};
                                       $displayed{'folder'} = $i;
                                   } elsif ($item eq "$contents[0]/index.html") {
                                       $env{'form.archive_'.$i} = 'display';
                                       $env{'form.archive_title_'.$i} = $env{'form.camtasia_moviename'};
                                       $displayed{'web'} = $i;
                                   } else {
                                       if ($item eq "$contents[0]/media") {
                                           push(@{$env{'form.archive_directory'}},$i);
                                       }
                                       $env{'form.archive_'.$i} = 'dependency';
                                   }
                                   $total ++;
                               }
                               for (my $i=1; $i<$total; $i++) {
                                   next if ($i == $displayed{'web'});
                                   next if ($i == $displayed{'folder'});
                                   $env{'form.archive_dependent_on_'.$i} = $displayed{'web'};
                               }
                               $env{'form.phase'} = 'decompress_cleanup';
                               $env{'form.archivedelete'} = 1;
                               $env{'form.archive_count'} = $total-1;
                               $output .=
                                   &process_extracted_files('coursedocs',$docudom,
                                                            $docuname,$destination,
                                                            $dir_root,$hiddenelem);
                           }
                       } else {
                           $warning = &mt('No new items extracted from archive file.');
                       }
                   } else {
                       $output = $display;
                       $error = &mt('An error occurred during extraction from the archive file.');
                   }
               }
           }
       }
       if ($error) {
           $output .= '<p class="LC_error">'.&mt('Not extracted.').'<br />'.
                      $error.'</p>'."\n";
       }
       if ($warning) {
           $output .= '<p class="LC_warning">'.$warning.'</p>'."\n";
       }
       return $output;
   }
   
   sub get_extracted {
       my ($docudom,$docuname,$currdir,$is_dir,$children,$parent,$contents,$dirorder,
           $titles,$wantform) = @_;
       my $count = 0;
       my $depth = 0;
       my $datatable;
       my @hierarchy;
       return unless ((ref($is_dir) eq 'HASH') && (ref($children) eq 'HASH') &&
                      (ref($parent) eq 'HASH') && (ref($contents) eq 'ARRAY') &&
                      (ref($dirorder) eq 'HASH') && (ref($titles) eq 'HASH'));
       foreach my $item (@{$contents}) {
           $count ++;
           @{$dirorder->{$count}} = @hierarchy;
           $titles->{$count} = $item;
           &archive_hierarchy($depth,$count,$parent,$children);
           if ($wantform) {
               $datatable .= &archive_row($is_dir->{$item},$item,
                                          $currdir,$depth,$count);
           }
           if ($is_dir->{$item}) {
               $depth ++;
               push(@hierarchy,$count);
               $parent->{$depth} = $count;
               $datatable .=
                   &recurse_extracted_archive("$currdir/$item",$docudom,$docuname,
                                              \$depth,\$count,\@hierarchy,$dirorder,
                                              $children,$parent,$titles,$wantform);
               $depth --;
               pop(@hierarchy);
           }
       }
       return ($count,$datatable);
   }
   
   sub recurse_extracted_archive {
       my ($currdir,$docudom,$docuname,$depth,$count,$hierarchy,$dirorder,
           $children,$parent,$titles,$wantform) = @_;
       my $result='';
       unless ((ref($depth)) && (ref($count)) && (ref($hierarchy) eq 'ARRAY') &&
               (ref($children) eq 'HASH') && (ref($parent) eq 'HASH') &&
               (ref($dirorder) eq 'HASH')) {
           return $result;
       }
       my $dirptr = 16384;
       my ($newdirlistref,$newlisterror) =
           &Apache::lonnet::dirlist($currdir,$docudom,$docuname,1);
       if (ref($newdirlistref) eq 'ARRAY') {
           foreach my $dir_line (@{$newdirlistref}) {
               my ($item,undef,undef,$testdir)=split(/\&/,$dir_line,5);
               unless ($item =~ /^\.+$/) {
                   $$count ++;
                   @{$dirorder->{$$count}} = @{$hierarchy};
                   $titles->{$$count} = $item;
                   &archive_hierarchy($$depth,$$count,$parent,$children);
   
                   my $is_dir;
                   if ($dirptr&$testdir) {
                       $is_dir = 1;
                   }
                   if ($wantform) {
                       $result .= &archive_row($is_dir,$item,$currdir,$$depth,$$count);
                   }
                   if ($is_dir) {
                       $$depth ++;
                       push(@{$hierarchy},$$count);
                       $parent->{$$depth} = $$count;
                       $result .=
                           &recurse_extracted_archive("$currdir/$item",$docudom,
                                                      $docuname,$depth,$count,
                                                      $hierarchy,$dirorder,$children,
                                                      $parent,$titles,$wantform);
                       $$depth --;
                       pop(@{$hierarchy});
                   }
               }
           }
       }
       return $result;
   }
   
   sub archive_hierarchy {
       my ($depth,$count,$parent,$children) =@_;
       if ((ref($parent) eq 'HASH') && (ref($children) eq 'HASH')) {
           if (exists($parent->{$depth})) {
                $children->{$parent->{$depth}} .= $count.':';
           }
       }
       return;
   }
   
   sub archive_row {
       my ($is_dir,$item,$currdir,$depth,$count) = @_;
       my ($name) = ($item =~ m{([^/]+)$});
       my %choices = &Apache::lonlocal::texthash (
                                          'display'    => 'Add as file',
                                          'dependency' => 'Include as dependency',
                                          'discard'    => 'Discard',
                                         );
       if ($is_dir) {
           $choices{'display'} = &mt('Add as folder'); 
       }
       my $output = &start_data_table_row().'<td align="right">'.$count.'</td>'."\n";
       my $offset = 0;
       foreach my $action ('display','dependency','discard') {
           $offset ++;
           if ($action ne 'display') {
               $offset ++;
           }  
           $output .= '<td><span class="LC_nobreak">'.
                      '<label><input type="radio" name="archive_'.$count.
                      '" id="archive_'.$action.'_'.$count.'" value="'.$action.'"';
           my $text = $choices{$action};
           if ($is_dir) {
               $output .= ' onclick="javascript:propagateCheck(this.form,'."'$count'".');"';
               if ($action eq 'display') {
                   $text = &mt('Add as folder');
               }
           } else {
               $output .= ' onclick="javascript:dependencyCheck(this.form,'."$count,$offset".');"';
   
           }
           $output .= ' />&nbsp;'.$choices{$action}.'</label></span>';
           if ($action eq 'dependency') {
               $output .= '<div id="arc_depon_'.$count.'" style="display:none;">'."\n".
                          &mt('Used by:').'&nbsp;<select name="archive_dependent_on_'.$count.'" '.
                          'onchange="propagateSelect(this.form,'."$count,$offset".')">'."\n".
                          '<option value=""></option>'."\n".
                          '</select>'."\n".
                          '</div>';
           } elsif ($action eq 'display') {
               $output .= '<div id="arc_title_'.$count.'" style="display:none;">'."\n".
                          &mt('Title:').'&nbsp;<input type="text" name="archive_title_'.$count.'" id="archive_title_'.$count.'" />'."\n".
                          '</div>';
           }
           $output .= '</td>';
       }
       $output .= '<td><input type="hidden" name="archive_content_'.$count.'" value="'.
                  &HTML::Entities::encode("$currdir/$item",'"<>&').'" />'.('&nbsp;' x 2);
       for (my $i=0; $i<$depth; $i++) {
           $output .= ('<img src="/adm/lonIcons/whitespace1.gif" class="LC_docs_spacer" alt="" />' x2)."\n";
       }
       if ($is_dir) {
           $output .= '<img src="/adm/lonIcons/navmap.folder.open.gif" alt="" />&nbsp;'."\n".
                      '<input type="hidden" name="archive_directory" value="'.$count.'" />'."\n";
       } else {
           $output .= '<input type="hidden" name="archive_file" value="'.$count.'" />'."\n";
       }
       $output .= '&nbsp;'.$name.'</td>'."\n".
                  &end_data_table_row();
       return $output;
   }
   
   sub archive_options_form {
       my ($form,$display,$count,$hiddenelem) = @_;
       my %lt = &Apache::lonlocal::texthash(
                  perm => 'Permanently remove archive file?',
                  hows => 'How should each extracted item be incorporated in the course?',
                  cont => 'Content actions for all',
                  addf => 'Add as folder/file',
                  incd => 'Include as dependency for a displayed file',
                  disc => 'Discard',
                  no   => 'No',
                  yes  => 'Yes',
                  save => 'Save',
       );
       my $output = <<"END";
   <form name="$form" method="post" action="">
   <p><span class="LC_nobreak">$lt{'perm'}&nbsp;
   <label>
     <input type="radio" name="archivedelete" value="0" checked="checked" />$lt{'no'}
   </label>
   &nbsp;
   <label>
     <input type="radio" name="archivedelete" value="1" />$lt{'yes'}</label>
   </span>
   </p>
   <input type="hidden" name="phase" value="decompress_cleanup" />
   <br />$lt{'hows'}
   <div class="LC_columnSection">
     <fieldset>
       <legend>$lt{'cont'}</legend>
       <input type="button" value="$lt{'addf'}" onclick="javascript:checkAll(document.$form,'display');" /> 
       &nbsp;&nbsp;<input type="button" value="$lt{'incd'}" onclick="javascript:checkAll(document.$form,'dependency');" />
       &nbsp;&nbsp;<input type="button" value="$lt{'disc'}" onclick="javascript:checkAll(document.$form,'discard');" />
     </fieldset>
   </div>
   END
       return $output.
              &start_data_table()."\n".
              $display."\n".
              &end_data_table()."\n".
              '<input type="hidden" name="archive_count" value="'.$count.'" />'.
              $hiddenelem.
              '<br /><input type="submit" name="archive_submit" value="'.$lt{'save'}.'" />'.
              '</form>';
   }
   
   sub archive_javascript {
       my ($startcount,$numitems,$titles,$children) = @_;
       return unless ((ref($titles) eq 'HASH') && (ref($children) eq 'HASH'));
       my $maintitle = $env{'form.comment'};
       my $scripttag = <<START;
   <script type="text/javascript">
   // <![CDATA[
   
   function checkAll(form,prefix) {
       var idstr =  new RegExp("^archive_"+prefix+"_\\\\d+\$");
       for (var i=0; i < form.elements.length; i++) {
           var id = form.elements[i].id;
           if ((id != '') && (id != undefined)) {
               if (idstr.test(id)) {
                   if (form.elements[i].type == 'radio') {
                       form.elements[i].checked = true;
                       var nostart = i-$startcount;
                       var offset = nostart%7;
                       var count = (nostart-offset)/7;    
                       dependencyCheck(form,count,offset);
                   }
               }
           }
       }
   }
   
   function propagateCheck(form,count) {
       if (count > 0) {
           var startelement = $startcount + ((count-1) * 7);
           for (var j=1; j<6; j++) {
               if ((j != 2) && (j != 4)) {
                   var item = startelement + j; 
                   if (form.elements[item].type == 'radio') {
                       if (form.elements[item].checked) {
                           containerCheck(form,count,j);
                           break;
                       }
                   }
               }
           }
       }
   }
   
   numitems = $numitems
   var titles = new Array(numitems);
   var parents = new Array(numitems);
   for (var i=0; i<numitems; i++) {
       parents[i] = new Array;
   }
   var maintitle = '$maintitle';
   
   START
   
       foreach my $container (sort { $a <=> $b } (keys(%{$children}))) {
           my @contents = split(/:/,$children->{$container});
           for (my $i=0; $i<@contents; $i ++) {
               $scripttag .= 'parents['.$container.']['.$i.'] = '.$contents[$i]."\n";
           }
       }
   
       foreach my $key (sort { $a <=> $b } (keys(%{$titles}))) {
           $scripttag .= "titles[$key] = '".$titles->{$key}."';\n";
       }
   
       $scripttag .= <<END;
   
   function containerCheck(form,count,offset) {
       if (count > 0) {
           dependencyCheck(form,count,offset);
           var item = (offset+$startcount)+7*(count-1);
           form.elements[item].checked = true;
           if(Object.prototype.toString.call(parents[count]) === '[object Array]') {
               if (parents[count].length > 0) {
                   for (var j=0; j<parents[count].length; j++) {
                       containerCheck(form,parents[count][j],offset);
                   }
               }
           }
       }
   }
   
   function dependencyCheck(form,count,offset) {
       if (count > 0) {
           var chosen = (offset+$startcount)+7*(count-1);
           var depitem = $startcount + ((count-1) * 7) + 4;
           var currtype = form.elements[depitem].type;
           if (form.elements[chosen].value == 'dependency') {
               document.getElementById('arc_depon_'+count).style.display='block'; 
               form.elements[depitem].options.length = 0;
               form.elements[depitem].options[0] = new Option('Select','',true,true);
               for (var i=1; i<=numitems; i++) {
                   if (i == count) {
                       continue;
                   }
                   var startelement = $startcount + (i-1) * 7;
                   for (var j=1; j<6; j++) {
                       if ((j != 2) && (j!= 4)) {
                           var item = startelement + j;
                           if (form.elements[item].type == 'radio') {
                               if (form.elements[item].checked) {
                                   if (form.elements[item].value == 'display') {
                                       var n = form.elements[depitem].options.length;
                                       form.elements[depitem].options[n] = new Option(titles[i],i,false,false);
                                   }
                               }
                           }
                       }
                   }
               }
           } else {
               document.getElementById('arc_depon_'+count).style.display='none';
               form.elements[depitem].options.length = 0;
               form.elements[depitem].options[0] = new Option('Select','',true,true);
           }
           titleCheck(form,count,offset);
       }
   }
   
   function propagateSelect(form,count,offset) {
       if (count > 0) {
           var item = (1+offset+$startcount)+7*(count-1);
           var picked = form.elements[item].options[form.elements[item].selectedIndex].value; 
           if (Object.prototype.toString.call(parents[count]) === '[object Array]') {
               if (parents[count].length > 0) {
                   for (var j=0; j<parents[count].length; j++) {
                       containerSelect(form,parents[count][j],offset,picked);
                   }
               }
           }
       }
   }
   
   function containerSelect(form,count,offset,picked) {
       if (count > 0) {
           var item = (offset+$startcount)+7*(count-1);
           if (form.elements[item].type == 'radio') {
               if (form.elements[item].value == 'dependency') {
                   if (form.elements[item+1].type == 'select-one') {
                       for (var i=0; i<form.elements[item+1].options.length; i++) {
                           if (form.elements[item+1].options[i].value == picked) {
                               form.elements[item+1].selectedIndex = i;
                               break;
                           }
                       }
                   }
                   if (Object.prototype.toString.call(parents[count]) === '[object Array]') {
                       if (parents[count].length > 0) {
                           for (var j=0; j<parents[count].length; j++) {
                               containerSelect(form,parents[count][j],offset,picked);
                           }
                       }
                   }
               }
           }
       }
   }
   
   function titleCheck(form,count,offset) {
       if (count > 0) {
           var chosen = (offset+$startcount)+7*(count-1);
           var depitem = $startcount + ((count-1) * 7) + 2;
           var currtype = form.elements[depitem].type;
           if (form.elements[chosen].value == 'display') {
               document.getElementById('arc_title_'+count).style.display='block';
               if ((count==1) && ((parents[count].length > 0) || (numitems == 1))) {
                   document.getElementById('archive_title_'+count).value=maintitle;
               }
           } else {
               document.getElementById('arc_title_'+count).style.display='none';
               if (currtype == 'text') { 
                   document.getElementById('archive_title_'+count).value='';
               }
           }
       }
       return;
   }
   
   // ]]>
   </script>
   END
       return $scripttag;
   }
   
   sub process_extracted_files {
       my ($context,$docudom,$docuname,$destination,$dir_root,$hiddenelem) = @_;
       my $numitems = $env{'form.archive_count'};
       return unless ($numitems);
       my @ids=&Apache::lonnet::current_machine_ids();
       my ($prefix,$pathtocheck,$dir,$ishome,$error,$warning,%toplevelitems,%is_dir,
           %folders,%containers,%mapinner,%prompttofetch);
       my $docuhome = &Apache::lonnet::homeserver($docuname,$docudom);
       if (grep(/^\Q$docuhome\E$/,@ids)) {
           $prefix = &LONCAPA::propath($docudom,$docuname);
           $pathtocheck = "$dir_root/$destination";
           $dir = $dir_root;
           $ishome = 1;
       } else {
           $prefix = $Apache::lonnet::perlvar{'lonDocRoot'};
           $pathtocheck = "$dir_root/$docudom/$docuname/$destination";
           $dir = "$dir_root/$docudom/$docuname";    
       }
       my $currdir = "$dir_root/$destination";
       (my $docstype,$mapinner{'0'}) = ($destination =~ m{^(docs|supplemental)/(\w+)/});
       if ($env{'form.folderpath'}) {
           my @items = split('&',$env{'form.folderpath'});
           $folders{'0'} = $items[-2];
           if ($env{'form.folderpath'} =~ /\:1$/) {
               $containers{'0'}='page';
           } else {  
               $containers{'0'}='sequence';
           }
       }
       my @archdirs = &get_env_multiple('form.archive_directory');
       if ($numitems) {
           for (my $i=1; $i<=$numitems; $i++) {
               my $path = $env{'form.archive_content_'.$i};
               if ($path =~ m{^\Q$pathtocheck\E/([^/]+)$}) {
                   my $item = $1;
                   $toplevelitems{$item} = $i;
                   if (grep(/^\Q$i\E$/,@archdirs)) {
                       $is_dir{$item} = 1;
                   }
               }
           }
       }
       my ($output,%children,%parent,%titles,%dirorder,$result);
       if (keys(%toplevelitems) > 0) {
           my @contents = sort(keys(%toplevelitems));
           (my $count,undef) = &get_extracted($docudom,$docuname,$currdir,\%is_dir,\%children,
                                              \%parent,\@contents,\%dirorder,\%titles);
       }
       my (%referrer,%orphaned,%todelete,%todeletedir,%newdest,%newseqid);
       if ($numitems) {
           for (my $i=1; $i<=$numitems; $i++) {
               next if ($env{'form.archive_'.$i} eq 'dependency');
               my $path = $env{'form.archive_content_'.$i};
               if ($path =~ /^\Q$pathtocheck\E/) {
                   if ($env{'form.archive_'.$i} eq 'discard') {
                       if ($prefix ne '' && $path ne '') {
                           if (-e $prefix.$path) {
                               if ((@archdirs > 0) && 
                                   (grep(/^\Q$i\E$/,@archdirs))) {
                                   $todeletedir{$prefix.$path} = 1;
                               } else {
                                   $todelete{$prefix.$path} = 1;
                               }
                           }
                       }
                   } elsif ($env{'form.archive_'.$i} eq 'display') {
                       my ($docstitle,$title,$url,$outer);
                       ($title) = ($path =~ m{/([^/]+)$});
                       $docstitle = $env{'form.archive_title_'.$i};
                       if ($docstitle eq '') {
                           $docstitle = $title;
                       }
                       $outer = 0;
                       if (ref($dirorder{$i}) eq 'ARRAY') {
                           if (@{$dirorder{$i}} > 0) {
                               foreach my $item (reverse(@{$dirorder{$i}})) {
                                   if ($env{'form.archive_'.$item} eq 'display') {
                                       $outer = $item;
                                       last;
                                   }
                               }
                           }
                       }
                       my ($errtext,$fatal) = 
                           &LONCAPA::map::mapread('/uploaded/'.$docudom.'/'.$docuname.
                                                  '/'.$folders{$outer}.'.'.
                                                  $containers{$outer});
                       next if ($fatal);
                       if ((@archdirs > 0) && (grep(/^\Q$i\E$/,@archdirs))) {
                           if ($context eq 'coursedocs') {
                               $mapinner{$i} = time;
                               $folders{$i} = 'default_'.$mapinner{$i};
                               $containers{$i} = 'sequence';
                               my $url = '/uploaded/'.$docudom.'/'.$docuname.'/'.
                                         $folders{$i}.'.'.$containers{$i};
                               my $newidx = &LONCAPA::map::getresidx();
                               $LONCAPA::map::resources[$newidx]=
                                   $docstitle.':'.$url.':false:normal:res';
                               push(@LONCAPA::map::order,$newidx);
                               my ($outtext,$errtext) =
                                   &LONCAPA::map::storemap('/uploaded/'.$docudom.'/'.
                                                           $docuname.'/'.$folders{$outer}.
                                                           '.'.$containers{$outer},1,1);
                               $newseqid{$i} = $newidx;
                               unless ($errtext) {
                                   $result .=  '<li>'.&mt('Folder: [_1] added to course',$docstitle).'</li>'."\n";
                               }
                           }
                       } else {
                           if ($context eq 'coursedocs') {
                               my $newidx=&LONCAPA::map::getresidx();
                               my $url = '/uploaded/'.$docudom.'/'.$docuname.'/'.
                                         $docstype.'/'.$mapinner{$outer}.'/'.$newidx.'/'.
                                         $title;
                               if (!-e "$prefix$dir/$docstype/$mapinner{$outer}") {
                                   mkdir("$prefix$dir/$docstype/$mapinner{$outer}",0755);
                               }
                               if (!-e "$prefix$dir/$docstype/$mapinner{$outer}/$newidx") {
                                   mkdir("$prefix$dir/$docstype/$mapinner{$outer}/$newidx");
                               }
                               if (-e "$prefix$dir/$docstype/$mapinner{$outer}/$newidx") {
                                   system("mv $prefix$path $prefix$dir/$docstype/$mapinner{$outer}/$newidx/$title");
                                   $newdest{$i} = "$prefix$dir/$docstype/$mapinner{$outer}/$newidx";
                                   unless ($ishome) {
                                       my $fetch = "$newdest{$i}/$title";
                                       $fetch =~ s/^\Q$prefix$dir\E//;
                                       $prompttofetch{$fetch} = 1;
                                   }
                               }
                               $LONCAPA::map::resources[$newidx]=
                                   $docstitle.':'.$url.':false:normal:res';
                               push(@LONCAPA::map::order, $newidx);
                               my ($outtext,$errtext)=
                                   &LONCAPA::map::storemap('/uploaded/'.$docudom.'/'.
                                                           $docuname.'/'.$folders{$outer}.
                                                           '.'.$containers{$outer},1,1);
                               unless ($errtext) {
                                   if (-e "$prefix$dir/$docstype/$mapinner{$outer}/$newidx/$title") {
                                       $result .= '<li>'.&mt('File: [_1] added to course',$docstitle).'</li>'."\n";
                                   }
                               }
                           }
                       }
                   }
               } else {
                   $warning .= &mt('Item extracted from archive: [_1] has unexpected path.',$path).'<br />'; 
               }
           }
           for (my $i=1; $i<=$numitems; $i++) {
               next unless ($env{'form.archive_'.$i} eq 'dependency');
               my $path = $env{'form.archive_content_'.$i};
               if ($path =~ /^\Q$pathtocheck\E/) {
                   my ($title) = ($path =~ m{/([^/]+)$});
                   $referrer{$i} = $env{'form.archive_dependent_on_'.$i};
                   if ($env{'form.archive_'.$referrer{$i}} eq 'display') {
                       if (ref($dirorder{$i}) eq 'ARRAY') {
                           my ($itemidx,$fullpath,$relpath);
                           if (ref($dirorder{$referrer{$i}}) eq 'ARRAY') {
                               my $container = $dirorder{$referrer{$i}}->[-1];
                               for (my $j=0; $j<@{$dirorder{$i}}; $j++) {
                                   if ($dirorder{$i}->[$j] eq $container) {
                                       $itemidx = $j;
                                   }
                               }
                           }
                           if ($itemidx eq '') {
                               $itemidx =  0;
                           } 
                           if (grep(/^\Q$referrer{$i}\E$/,@archdirs)) {
                               if ($mapinner{$referrer{$i}}) {
                                   $fullpath = "$prefix$dir/$docstype/$mapinner{$referrer{$i}}";
                                   for (my $j=$itemidx; $j<@{$dirorder{$i}}; $j++) {
                                       if (grep(/^\Q$dirorder{$i}->[$j]\E$/,@archdirs)) {
                                           unless (defined($newseqid{$dirorder{$i}->[$j]})) {
                                               $fullpath .= '/'.$titles{$dirorder{$i}->[$j]};
                                               $relpath .= '/'.$titles{$dirorder{$i}->[$j]};
                                               if (!-e $fullpath) {
                                                   mkdir($fullpath,0755);
                                               }
                                           }
                                       } else {
                                           last;
                                       }
                                   }
                               }
                           } elsif ($newdest{$referrer{$i}}) {
                               $fullpath = $newdest{$referrer{$i}};
                               for (my $j=$itemidx; $j<@{$dirorder{$i}}; $j++) {
                                   if ($env{'form.archive_'.$dirorder{$i}->[$j]} eq 'discard') {
                                       $orphaned{$i} = $env{'form.archive_'.$dirorder{$i}->[$j]};
                                       last;
                                   } elsif (grep(/^\Q$dirorder{$i}->[$j]\E$/,@archdirs)) {
                                       unless (defined($newseqid{$dirorder{$i}->[$j]})) {
                                           $fullpath .= '/'.$titles{$dirorder{$i}->[$j]};
                                           $relpath .= '/'.$titles{$dirorder{$i}->[$j]};
                                           if (!-e $fullpath) {
                                               mkdir($fullpath,0755);
                                           }
                                       }
                                   } else {
                                       last;
                                   }
                               }
                           }
                           if ($fullpath ne '') {
                               if (-e "$prefix$path") {
                                   system("mv $prefix$path $fullpath/$title");
                               }
                               if (-e "$fullpath/$title") {
                                   my $showpath;
                                   if ($relpath ne '') {
                                       $showpath = "$relpath/$title";
                                   } else {
                                       $showpath = "/$title";
                                   } 
                                   $result .= '<li>'.&mt('[_1] included as a dependency',$showpath).'</li>'."\n";
                               } 
                               unless ($ishome) {
                                   my $fetch = "$fullpath/$title";
                                   $fetch =~ s/^\Q$prefix$dir\E//; 
                                   $prompttofetch{$fetch} = 1;
                               }
                           }
                       }
                   } elsif ($env{'form.archive_'.$referrer{$i}} eq 'discard') {
                       $warning .= &mt('[_1] is a dependency of [_2], which was discarded.',
                                       $path,$env{'form.archive_content_'.$referrer{$i}}).'<br />';
                   }
               } else {
                   $warning .= &mt('Item extracted from archive: [_1] has unexpected path.',$path).'<br />'; 
               }
           }
           if (keys(%todelete)) {
               foreach my $key (keys(%todelete)) {
                   unlink($key);
               }
           }
           if (keys(%todeletedir)) {
               foreach my $key (keys(%todeletedir)) {
                   rmdir($key);
               }
           }
           foreach my $dir (sort(keys(%is_dir))) {
               if (($pathtocheck ne '') && ($dir ne ''))  {
                   &cleanup_empty_dirs($prefix."$pathtocheck/$dir");
               }
           }
           if ($result ne '') {
               $output .= '<ul>'."\n".
                          $result."\n".
                          '</ul>';
           }
           unless ($ishome) {
               my $replicationfail;
               foreach my $item (keys(%prompttofetch)) {
                   my $fetchresult= &Apache::lonnet::reply('fetchuserfile:'.$item,$docuhome);
                   unless ($fetchresult eq 'ok') {
                       $replicationfail .= '<li>'.$item.'</li>'."\n";
                   }
               }
               if ($replicationfail) {
                   $output .= '<p class="LC_error">'.
                              &mt('Course home server failed to retrieve:').'<ul>'.
                              $replicationfail.
                              '</ul></p>';
               }
           }
       } else {
           $warning = &mt('No items found in archive.');
       }
       if ($error) {
           $output .= '<p class="LC_error">'.&mt('Not extracted.').'<br />'.
                      $error.'</p>'."\n";
       }
       if ($warning) {
           $output .= '<p class="LC_warning">'.$warning.'</p>'."\n";
       }
       return $output;
   }
   
   sub cleanup_empty_dirs {
       my ($path) = @_;
       if (($path ne '') && (-d $path)) {
           if (opendir(my $dirh,$path)) {
               my @dircontents = grep(!/^\./,readdir($dirh));
               my $numitems = 0;
               foreach my $item (@dircontents) {
                   if (-d "$path/$item") {
                       &recurse_dirs("$path/$item");
                       if (-e "$path/$item") {
                           $numitems ++;
                       }
                   } else {
                       $numitems ++;
                   }
               }
               if ($numitems == 0) {
                   rmdir($path);
               }
               closedir($dirh);
           }
       }
       return;
   }
   
   =pod
   
   =item &get_folder_hierarchy()
   
   Provides hierarchy of names of folders/sub-folders containing the current
   item,
   
   Inputs: 3
        - $navmap - navmaps object
   
        - $map - url for map (either the trigger itself, or map containing
                              the resource, which is the trigger).
   
        - $showitem - 1 => show title for map itself; 0 => do not show.
   
   Outputs: 1 @pathitems - array of folder/subfolder names.
   
   =cut
   
   sub get_folder_hierarchy {
       my ($navmap,$map,$showitem) = @_;
       my @pathitems;
       if (ref($navmap)) {
           my $mapres = $navmap->getResourceByUrl($map);
           if (ref($mapres)) {
               my $pcslist = $mapres->map_hierarchy();
               if ($pcslist ne '') {
                   my @pcs = split(/,/,$pcslist);
                   foreach my $pc (@pcs) {
                       if ($pc == 1) {
                           push(@pathitems,&mt('Main Course Documents'));
                       } else {
                           my $res = $navmap->getByMapPc($pc);
                           if (ref($res)) {
                               my $title = $res->compTitle();
                               $title =~ s/\W+/_/g;
                               if ($title ne '') {
                                   push(@pathitems,$title);
                               }
                           }
                       }
                   }
               }
               if ($showitem) {
                   if ($mapres->{ID} eq '0.0') {
                       push(@pathitems,&mt('Main Course Documents'));
                   } else {
                       my $maptitle = $mapres->compTitle();
                       $maptitle =~ s/\W+/_/g;
                       if ($maptitle ne '') {
                           push(@pathitems,$maptitle);
                       }
                   }
               }
           }
       }
       return @pathitems;
   }
   
   =pod
   
   =item * &get_turnedin_filepath()
   
   Determines path in a user's portfolio file for storage of files uploaded
   to a specific essayresponse or dropbox item.
   
   Inputs: 3 required + 1 optional.
   $symb is symb for resource, $uname and $udom are for current user (required).
   $caller is optional (can be "submission", if routine is called when storing
   an upoaded file when "Submit Answer" button was pressed).
   
   Returns array containing $path and $multiresp. 
   $path is path in portfolio.  $multiresp is 1 if this resource contains more
   than one file upload item.  Callers of routine should append partid as a 
   subdirectory to $path in cases where $multiresp is 1.
   
   Called by: homework/essayresponse.pm and homework/structuretags.pm
   
   =cut
   
   sub get_turnedin_filepath {
       my ($symb,$uname,$udom,$caller) = @_;
       my ($map,$resid,$resurl)=&Apache::lonnet::decode_symb($symb);
       my $turnindir;
       my %userhash = &Apache::lonnet::userenvironment($udom,$uname,'turnindir');
       $turnindir = $userhash{'turnindir'};
       my ($path,$multiresp);
       if ($turnindir eq '') {
           if ($caller eq 'submission') {
               $turnindir = &mt('turned in');
               $turnindir =~ s/\W+/_/g;
               my %newhash = (
                               'turnindir' => $turnindir,
                             );
               &Apache::lonnet::put('environment',\%newhash,$udom,$uname);
           }
       }
       if ($turnindir ne '') {
           $path = '/'.$turnindir.'/';
           my ($multipart,$turnin,@pathitems);
           my $navmap = Apache::lonnavmaps::navmap->new();
           if (defined($navmap)) {
               my $mapres = $navmap->getResourceByUrl($map);
               if (ref($mapres)) {
                   my $pcslist = $mapres->map_hierarchy();
                   if ($pcslist ne '') {
                       foreach my $pc (split(/,/,$pcslist)) {
                           my $res = $navmap->getByMapPc($pc);
                           if (ref($res)) {
                               my $title = $res->compTitle();
                               $title =~ s/\W+/_/g;
                               if ($title ne '') {
                                   push(@pathitems,$title);
                               }
                           }
                       }
                   }
                   my $maptitle = $mapres->compTitle();
                   $maptitle =~ s/\W+/_/g;
                   if ($maptitle ne '') {
                       push(@pathitems,$maptitle);
                   }
                   unless ($env{'request.state'} eq 'construct') {
                       my $res = $navmap->getBySymb($symb);
                       if (ref($res)) {
                           my $partlist = $res->parts();
                           my $totaluploads = 0;
                           if (ref($partlist) eq 'ARRAY') {
                               foreach my $part (@{$partlist}) {
                                   my @types = $res->responseType($part);
                                   my @ids = $res->responseIds($part);
                                   for (my $i=0; $i < scalar(@ids); $i++) {
                                       if ($types[$i] eq 'essay') {
                                           my $partid = $part.'_'.$ids[$i];
                                           if (&Apache::lonnet::EXT("resource.$partid.uploadedfiletypes") ne '') {
                                               $totaluploads ++;
                                           }
                                       }
                                   }
                               }
                               if ($totaluploads > 1) {
                                   $multiresp = 1;
                               }
                           }
                       }
                   }
               } else {
                   return;
               }
           } else {
               return;
           }
           my $restitle=&Apache::lonnet::gettitle($symb);
           $restitle =~ s/\W+/_/g;
           if ($restitle eq '') {
               $restitle = ($resurl =~ m{/[^/]+$});
               if ($restitle eq '') {
                   $restitle = time;
               }
           }
           push(@pathitems,$restitle);
           $path .= join('/',@pathitems);
       }
       return ($path,$multiresp);
   }
   
 =pod  =pod
   
 =back  =back
Line 10716  sub commit_studentrole { Line 13291  sub commit_studentrole {
             $result = $modify_section_result;              $result = $modify_section_result;
         } elsif ($secchange == 1) {          } elsif ($secchange == 1) {
             if ($oldsec eq '') {              if ($oldsec eq '') {
                 $$logmsg .= &mt('Error when attempting to expire existing role without a section for [_1] in course [_3] -error: ',$uname,$cid).' '.$expire_role_result.$linefeed;                  $$logmsg .= &mt('Error when attempting to expire existing role without a section for [_1] in course [_2] -error: ',$uname,$cid).' '.$expire_role_result.$linefeed;
             } else {              } else {
                 $$logmsg .= &mt('Error when attempting to expire existing role for [_1] in section [_2] in course [_3] -error: ',$uname,$oldsec,$cid).' '.$expire_role_result.$linefeed;                  $$logmsg .= &mt('Error when attempting to expire existing role for [_1] in section [_2] in course [_3] -error: ',$uname,$oldsec,$cid).' '.$expire_role_result.$linefeed;
             }              }
Line 11153  sub construct_course { Line 13728  sub construct_course {
 ############################################################  ############################################################
 ############################################################  ############################################################
   
   #SD
   # only Community and Course, or anything else?
 sub course_type {  sub course_type {
     my ($cid) = @_;      my ($cid) = @_;
     if (!defined($cid)) {      if (!defined($cid)) {
Line 11268  sub init_user_environment { Line 13845  sub init_user_environment {
   
 # See if old ID present, if so, remove  # See if old ID present, if so, remove
   
     my ($filename,$cookie,$userroles);      my ($filename,$cookie,$userroles,$firstaccenv,$timerintenv);
     my $now=time;      my $now=time;
   
     if ($public) {      if ($public) {
Line 11306  sub init_user_environment { Line 13883  sub init_user_environment {
           
 # Initialize roles  # Initialize roles
   
  $userroles=&Apache::lonnet::rolesinit($domain,$username,$authhost);   ($userroles,$firstaccenv,$timerintenv) = 
               &Apache::lonnet::rolesinit($domain,$username,$authhost);
     }      }
 # ------------------------------------ Check browser type and MathML capability  # ------------------------------------ Check browser type and MathML capability
   
Line 11318  sub init_user_environment { Line 13896  sub init_user_environment {
     my %userenv = &Apache::lonnet::dump('environment',$domain,$username);      my %userenv = &Apache::lonnet::dump('environment',$domain,$username);
     my ($tmp) = keys(%userenv);      my ($tmp) = keys(%userenv);
     if ($tmp !~ /^(con_lost|error|no_such_host)/i) {      if ($tmp !~ /^(con_lost|error|no_such_host)/i) {
  # default remote control to off  
  if ($userenv{'remote'} ne 'on') { $userenv{'remote'} = 'off'; }  
     } else {      } else {
  undef(%userenv);   undef(%userenv);
     }      }
     if (($userenv{'interface'}) && (!$form->{'interface'})) {      if (($userenv{'interface'}) && (!$form->{'interface'})) {
  $form->{'interface'}=$userenv{'interface'};   $form->{'interface'}=$userenv{'interface'};
     }      }
     $env{'environment.remote'}=$userenv{'remote'};  
     if ($userenv{'texengine'} eq 'ttm') { $clientmathml=1; }      if ($userenv{'texengine'} eq 'ttm') { $clientmathml=1; }
   
 # --------------- Do not trust query string to be put directly into environment  # --------------- Do not trust query string to be put directly into environment
Line 11358  sub init_user_environment { Line 13933  sub init_user_environment {
     $initial_env{"browser.localres"}   = $form->{'localres'};      $initial_env{"browser.localres"}   = $form->{'localres'};
         }          }
   
  if ($public) {  
     $initial_env{"environment.remote"} = "off";  
  }  
  if ($form->{'interface'}) {   if ($form->{'interface'}) {
     $form->{'interface'}=~s/\W//gs;      $form->{'interface'}=~s/\W//gs;
     $initial_env{"browser.interface"} = $form->{'interface'};      $initial_env{"browser.interface"} = $form->{'interface'};
     $env{'browser.interface'}=$form->{'interface'};      $env{'browser.interface'}=$form->{'interface'};
  }   }
   
         my %is_adv = ( is_adv => $env{'user.adv'} );          my %is_adv = ( is_adv => $env{'user.adv'} );
         my %domdef = &Apache::lonnet::get_domain_defaults($domain);          my %domdef;
           unless ($domain eq 'public') {
               %domdef = &Apache::lonnet::get_domain_defaults($domain);
           }
   
         foreach my $tool ('aboutme','blog','portfolio') {          foreach my $tool ('aboutme','blog','webdav','portfolio') {
             $userenv{'availabletools.'.$tool} =               $userenv{'availabletools.'.$tool} = 
                 &Apache::lonnet::usertools_access($username,$domain,$tool,'reload',                  &Apache::lonnet::usertools_access($username,$domain,$tool,'reload',
                                                   undef,\%userenv,\%domdef,\%is_adv);                                                    undef,\%userenv,\%domdef,\%is_adv);
Line 11382  sub init_user_environment { Line 13958  sub init_user_environment {
                                                   \%userenv,\%domdef,\%is_adv);                                                    \%userenv,\%domdef,\%is_adv);
         }          }
   
           $userenv{'canrequest.author'} =
               &Apache::lonnet::usertools_access($username,$domain,'requestauthor',
                                           'reload','requestauthor',
                                           \%userenv,\%domdef,\%is_adv);
           my %reqauthor = &Apache::lonnet::get('requestauthor',['author_status','author'],
                                                $domain,$username);
           my $reqstatus = $reqauthor{'author_status'};
           if ($reqstatus eq 'approval' || $reqstatus eq 'approved') { 
               if (ref($reqauthor{'author'}) eq 'HASH') {
                   $userenv{'requestauthorqueued'} = $reqstatus.':'.
                                                     $reqauthor{'author'}{'timestamp'};
               }
           }
   
  $env{'user.environment'} = "$lonids/$cookie.id";   $env{'user.environment'} = "$lonids/$cookie.id";
   
  if (tie(my %disk_env,'GDBM_File',"$lonids/$cookie.id",   if (tie(my %disk_env,'GDBM_File',"$lonids/$cookie.id",
  &GDBM_WRCREAT(),0640)) {   &GDBM_WRCREAT(),0640)) {
     &_add_to_env(\%disk_env,\%initial_env);      &_add_to_env(\%disk_env,\%initial_env);
     &_add_to_env(\%disk_env,\%userenv,'environment.');      &_add_to_env(\%disk_env,\%userenv,'environment.');
     &_add_to_env(\%disk_env,$userroles);      &_add_to_env(\%disk_env,$userroles);
               if (ref($firstaccenv) eq 'HASH') {
                   &_add_to_env(\%disk_env,$firstaccenv);
               }
               if (ref($timerintenv) eq 'HASH') {
                   &_add_to_env(\%disk_env,$timerintenv);
               }
     if (ref($args->{'extra_env'})) {      if (ref($args->{'extra_env'})) {
  &_add_to_env(\%disk_env,$args->{'extra_env'});   &_add_to_env(\%disk_env,$args->{'extra_env'});
     }      }
Line 11424  sub get_symb { Line 14020  sub get_symb {
     my $symb=($env{'form.symb'} ne '' ? $env{'form.symb'} : (&Apache::lonnet::symbread($url)));      my $symb=($env{'form.symb'} ne '' ? $env{'form.symb'} : (&Apache::lonnet::symbread($url)));
     if ($symb eq '') {      if ($symb eq '') {
         if (!$silent) {          if (!$silent) {
             $request->print("Unable to handle ambiguous references:$url:.");              if (ref($request)) { 
                   $request->print("Unable to handle ambiguous references:$url:.");
               }
             return ();              return ();
         }          }
     }      }
Line 11488  sub build_release_hashes { Line 14086  sub build_release_hashes {
     return;      return;
 }  }
   
   sub update_content_constraints {
       my ($cdom,$cnum,$chome,$cid) = @_;
       my %curr_reqd_hash = &Apache::lonnet::userenvironment($cdom,$cnum,'internal.releaserequired');
       my ($reqdmajor,$reqdminor) = split(/\./,$curr_reqd_hash{'internal.releaserequired'});
       my %checkresponsetypes;
       foreach my $key (keys(%Apache::lonnet::needsrelease)) {
           my ($item,$name,$value) = split(/:/,$key);
           if ($item eq 'resourcetag') {
               if ($name eq 'responsetype') {
                   $checkresponsetypes{$value} = $Apache::lonnet::needsrelease{$key}
               }
           }
       }
       my $navmap = Apache::lonnavmaps::navmap->new();
       if (defined($navmap)) {
           my %allresponses;
           foreach my $res ($navmap->retrieveResources(undef,sub { $_[0]->is_problem() },1,0)) {
               my %responses = $res->responseTypes();
               foreach my $key (keys(%responses)) {
                   next unless(exists($checkresponsetypes{$key}));
                   $allresponses{$key} += $responses{$key};
               }
           }
           foreach my $key (keys(%allresponses)) {
               my ($major,$minor) = split(/\./,$checkresponsetypes{$key});
               if (($major > $reqdmajor) || ($major == $reqdmajor && $minor > $reqdminor)) {
                   ($reqdmajor,$reqdminor) = ($major,$minor);
               }
           }
           undef($navmap);
       }
       unless (($reqdmajor eq '') && ($reqdminor eq '')) {
           &Apache::lonnet::update_released_required($reqdmajor.'.'.$reqdminor,$cdom,$cnum,$chome,$cid);
       }
       return;
   }
   
   sub parse_supplemental_title {
       my ($title) = @_;
   
       my ($foldertitle,$renametitle);
       if ($title =~ /&amp;&amp;&amp;/) {
           $title = &HTML::Entites::decode($title);
       }
       if ($title =~ m/^(\d+)___&&&___($match_username)___&&&___($match_domain)___&&&___(.*)$/) {
           $renametitle=$4;
           my ($time,$uname,$udom) = ($1,$2,$3);
           $foldertitle=&Apache::lontexconvert::msgtexconverted($4);
           my $name =  &plainname($uname,$udom);
           $name = &HTML::Entities::encode($name,'"<>&\'');
           $renametitle = &HTML::Entities::encode($renametitle,'"<>&\'');
           $title='<i>'.&Apache::lonlocal::locallocaltime($time).'</i> '.
               $name.': <br />'.$foldertitle;
       }
       if (wantarray) {
           return ($title,$foldertitle,$renametitle);
       }
       return $title;
   }
   
   sub symb_to_docspath {
       my ($symb) = @_;
       return unless ($symb);
       my ($mapurl,$id,$resurl) = &Apache::lonnet::decode_symb($symb);
       if ($resurl=~/\.(sequence|page)$/) {
           $mapurl=$resurl;
       } elsif ($resurl eq 'adm/navmaps') {
           $mapurl=$env{'course.'.$env{'request.course.id'}.'.url'};
       }
       my $mapresobj;
       my $navmap = Apache::lonnavmaps::navmap->new();
       if (ref($navmap)) {
           $mapresobj = $navmap->getResourceByUrl($mapurl);
       }
       $mapurl=~s{^.*/([^/]+)\.(\w+)$}{$1};
       my $type=$2;
       my $path;
       if (ref($mapresobj)) {
           my $pcslist = $mapresobj->map_hierarchy();
           if ($pcslist ne '') {
               foreach my $pc (split(/,/,$pcslist)) {
                   next if ($pc <= 1);
                   my $res = $navmap->getByMapPc($pc);
                   if (ref($res)) {
                       my $thisurl = $res->src();
                       $thisurl=~s{^.*/([^/]+)\.\w+$}{$1};
                       my $thistitle = $res->title();
                       $path .= '&'.
                                &Apache::lonhtmlcommon::entity_encode($thisurl).'&'.
                                &Apache::lonhtmlcommon::entity_encode($thistitle).
                                ':'.$res->randompick().
                                ':'.$res->randomout().
                                ':'.$res->encrypted().
                                ':'.$res->randomorder().
                                ':'.$res->is_page();
                   }
               }
           }
           $path =~ s/^\&//;
           my $maptitle = $mapresobj->title();
           if ($mapurl eq 'default') {
               $maptitle = 'Main Course Documents';
           }
           $path .= (($path ne '')? '&' : '').
                    &Apache::lonhtmlcommon::entity_encode($mapurl).'&'.
                    &Apache::lonhtmlcommon::entity_encode($maptitle).
                    ':'.$mapresobj->randompick().
                    ':'.$mapresobj->randomout().
                    ':'.$mapresobj->encrypted().
                    ':'.$mapresobj->randomorder().
                    ':'.$mapresobj->is_page();
       } else {
           my $maptitle = &Apache::lonnet::gettitle($mapurl);
           my $ispage = (($type eq 'page')? 1 : '');
           if ($mapurl eq 'default') {
               $maptitle = 'Main Course Documents';
           }
           $path = &Apache::lonhtmlcommon::entity_encode($mapurl).'&'.
                   &Apache::lonhtmlcommon::entity_encode($maptitle).':::::'.$ispage;
       }
       unless ($mapurl eq 'default') {
           $path = 'default&'.
                   &Apache::lonhtmlcommon::entity_encode('Main Course Documents').
                   ':::::&'.$path;
       }
       return $path;
   }
   
   sub captcha_display {
       my ($context,$lonhost) = @_;
       my ($output,$error);
       my ($captcha,$pubkey,$privkey) = &get_captcha_config($context,$lonhost);
       if ($captcha eq 'original') {
           $output = &create_captcha();
           unless ($output) {
               $error = 'captcha'; 
           }
       } elsif ($captcha eq 'recaptcha') {
           $output = &create_recaptcha($pubkey);
           unless ($output) {
               $error = 'recaptcha'; 
           }
       }
       return ($output,$error);
   }
   
   sub captcha_response {
       my ($context,$lonhost) = @_;
       my ($captcha_chk,$captcha_error);
       my ($captcha,$pubkey,$privkey) = &get_captcha_config($context,$lonhost);
       if ($captcha eq 'original') {
           ($captcha_chk,$captcha_error) = &check_captcha();
       } elsif ($captcha eq 'recaptcha') {
           $captcha_chk = &check_recaptcha($privkey);
       } else {
           $captcha_chk = 1;
       }
       return ($captcha_chk,$captcha_error);
   }
   
   sub get_captcha_config {
       my ($context,$lonhost) = @_;
       my ($captcha,$pubkey,$privkey,$hashtocheck);
       my $hostname = &Apache::lonnet::hostname($lonhost);
       my $serverhomeID = &Apache::lonnet::get_server_homeID($hostname);
       my $serverhomedom = &Apache::lonnet::host_domain($serverhomeID);
       if ($context eq 'usercreation') {
           my %domconfig = &Apache::lonnet::get_dom('configuration',[$context],$serverhomedom);
           if (ref($domconfig{$context}) eq 'HASH') {
               $hashtocheck = $domconfig{$context}{'cancreate'};
               if (ref($hashtocheck) eq 'HASH') {
                   if ($hashtocheck->{'captcha'} eq 'recaptcha') {
                       if (ref($hashtocheck->{'recaptchakeys'}) eq 'HASH') {
                           $pubkey = $hashtocheck->{'recaptchakeys'}{'public'};
                           $privkey = $hashtocheck->{'recaptchakeys'}{'private'};
                       }
                       if ($privkey && $pubkey) {
                           $captcha = 'recaptcha';
                       } else {
                           $captcha = 'original';
                       }
                   } elsif ($hashtocheck->{'captcha'} ne 'notused') {
                       $captcha = 'original';
                   }
               }
           } else {
               $captcha = 'captcha';
           }
       } elsif ($context eq 'login') {
           my %domconfhash = &Apache::loncommon::get_domainconf($serverhomedom);
           if ($domconfhash{$serverhomedom.'.login.captcha'} eq 'recaptcha') {
               $pubkey = $domconfhash{$serverhomedom.'.login.recaptchakeys_public'};
               $privkey = $domconfhash{$serverhomedom.'.login.recaptchakeys_private'};
               if ($privkey && $pubkey) {
                   $captcha = 'recaptcha';
               } else {
                   $captcha = 'original';
               }
           } elsif ($domconfhash{$serverhomedom.'.login.captcha'} eq 'original') {
               $captcha = 'original';
           }
       }
       return ($captcha,$pubkey,$privkey);
   }
   
   sub create_captcha {
       my %captcha_params = &captcha_settings();
       my ($output,$maxtries,$tries) = ('',10,0);
       while ($tries < $maxtries) {
           $tries ++;
           my $captcha = Authen::Captcha->new (
                                              output_folder => $captcha_params{'output_dir'},
                                              data_folder   => $captcha_params{'db_dir'},
                                             );
           my $md5sum = $captcha->generate_code($captcha_params{'numchars'});
   
           if (-e $Apache::lonnet::perlvar{'lonCaptchaDir'}.'/'.$md5sum.'.png') {
               $output = '<input type="hidden" name="crypt" value="'.$md5sum.'" />'."\n".
                         &mt('Type in the letters/numbers shown below').'&nbsp;'.
                        '<input type="text" size="5" name="code" value="" /><br />'.
                        '<img src="'.$captcha_params{'www_output_dir'}.'/'.$md5sum.'.png" />';
               last;
           }
       }
       return $output;
   }
   
   sub captcha_settings {
       my %captcha_params = (
                              output_dir     => $Apache::lonnet::perlvar{'lonCaptchaDir'},
                              www_output_dir => "/captchaspool",
                              db_dir         => $Apache::lonnet::perlvar{'lonCaptchaDb'},
                              numchars       => '5',
                            );
       return %captcha_params;
   }
   
   sub check_captcha {
       my ($captcha_chk,$captcha_error);
       my $code = $env{'form.code'};
       my $md5sum = $env{'form.crypt'};
       my %captcha_params = &captcha_settings();
       my $captcha = Authen::Captcha->new(
                         output_folder => $captcha_params{'output_dir'},
                         data_folder   => $captcha_params{'db_dir'},
                     );
       my $captcha_chk = $captcha->check_code($code,$md5sum);
       my %captcha_hash = (
                           0       => 'Code not checked (file error)',
                          -1      => 'Failed: code expired',
                          -2      => 'Failed: invalid code (not in database)',
                          -3      => 'Failed: invalid code (code does not match crypt)',
       );
       if ($captcha_chk != 1) {
           $captcha_error = $captcha_hash{$captcha_chk}
       }
       return ($captcha_chk,$captcha_error);
   }
   
   sub create_recaptcha {
       my ($pubkey) = @_;
       my $captcha = Captcha::reCAPTCHA->new;
       return $captcha->get_options_setter({theme => 'white'})."\n".
              $captcha->get_html($pubkey).
              &mt('If either word is hard to read, [_1] will replace them.',
                  '<image src="/res/adm/pages/refresh.gif" alt="reCAPTCHA refresh" />').
              '<br /><br />';
   }
   
   sub check_recaptcha {
       my ($privkey) = @_;
       my $captcha_chk;
       my $captcha = Captcha::reCAPTCHA->new;
       my $captcha_result =
           $captcha->check_answer(
                                   $privkey,
                                   $ENV{'REMOTE_ADDR'},
                                   $env{'form.recaptcha_challenge_field'},
                                   $env{'form.recaptcha_response_field'},
                                 );
       if ($captcha_result->{is_valid}) {
           $captcha_chk = 1;
       }
       return $captcha_chk;
   }
   
 =pod  =pod
   
 =back  =back

Removed from v.1.948.2.27  
changed lines
  Added in v.1.1107


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