Diff for /loncom/interface/loncommon.pm between versions 1.1075.2.161.2.14 and 1.1235

version 1.1075.2.161.2.14, 2023/01/22 17:05:21 version 1.1235, 2016/02/20 00:12:39
Line 61  use POSIX qw(strftime mktime); Line 61  use POSIX qw(strftime mktime);
 use Apache::lonmenu();  use Apache::lonmenu();
 use Apache::lonenc();  use Apache::lonenc();
 use Apache::lonlocal;  use Apache::lonlocal;
 use Apache::lonnavmaps();  use Apache::lonnet();
 use HTML::Entities;  use HTML::Entities;
 use Apache::lonhtmlcommon();  use Apache::lonhtmlcommon();
 use Apache::loncoursedata();  use Apache::loncoursedata();
Line 71  use Apache::lonuserutils(); Line 71  use Apache::lonuserutils();
 use Apache::lonuserstate();  use Apache::lonuserstate();
 use Apache::courseclassifier();  use Apache::courseclassifier();
 use LONCAPA qw(:DEFAULT :match);  use LONCAPA qw(:DEFAULT :match);
 use LONCAPA::map();  
 use HTTP::Request;  
 use DateTime::TimeZone;  use DateTime::TimeZone;
 use DateTime::Locale;  use DateTime::Locale::Catalog;
 use Encode();  use Encode();
   use Text::Aspell;
 use Authen::Captcha;  use Authen::Captcha;
 use Captcha::reCAPTCHA;  use Captcha::reCAPTCHA;
 use JSON::DWIW;  use JSON::DWIW;
 use LWP::UserAgent;  use LWP::UserAgent;
 use Crypt::DES;  use Crypt::DES;
 use DynaLoader; # for Crypt::DES version  use DynaLoader; # for Crypt::DES version
 use File::Copy();  use MIME::Lite;
 use File::Path();  use MIME::Types;
 use String::CRC32();  
 use Short::URL();  
   
 # ---------------------------------------------- Designs  # ---------------------------------------------- Designs
 use vars qw(%defaultdesign);  use vars qw(%defaultdesign);
Line 170  sub ssi_with_retries { Line 167  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; # For choosing hyphenation in <transl..>
 my %latex_language_bykey; # for choosing hyphenation from metadata  my %latex_language_bykey; # for choosing hyphenation from metadata
 my %cprtag;  my %cprtag;
Line 200  BEGIN { Line 198  BEGIN {
     {      {
         my $langtabfile = $Apache::lonnet::perlvar{'lonTabDir'}.          my $langtabfile = $Apache::lonnet::perlvar{'lonTabDir'}.
                                    '/language.tab';                                     '/language.tab';
         if ( open(my $fh,'<',$langtabfile) ) {          if ( open(my $fh,"<$langtabfile") ) {
             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,$latex)=(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) {   if ($latex) {
     $latex_language_bykey{$key} = $latex;      $latex_language_bykey{$key} = $latex;
     $latex_language{$two} = $latex;      $latex_language{$code} = $latex;
  }   }
             }              }
             close($fh);              close($fh);
Line 221  BEGIN { Line 220  BEGIN {
     {      {
         my $copyrightfile = $Apache::lonnet::perlvar{'lonIncludes'}.          my $copyrightfile = $Apache::lonnet::perlvar{'lonIncludes'}.
                                   '/copyright.tab';                                    '/copyright.tab';
         if ( open (my $fh,'<',$copyrightfile) ) {          if ( open (my $fh,"<$copyrightfile") ) {
             while (my $line = <$fh>) {              while (my $line = <$fh>) {
                 next if ($line=~/^\#/);                  next if ($line=~/^\#/);
                 chomp($line);                  chomp($line);
Line 235  BEGIN { Line 234  BEGIN {
     {      {
         my $sourcecopyrightfile = $Apache::lonnet::perlvar{'lonIncludes'}.          my $sourcecopyrightfile = $Apache::lonnet::perlvar{'lonIncludes'}.
                                   '/source_copyright.tab';                                    '/source_copyright.tab';
         if ( open (my $fh,'<',$sourcecopyrightfile) ) {          if ( open (my $fh,"<$sourcecopyrightfile") ) {
             while (my $line = <$fh>) {              while (my $line = <$fh>) {
                 next if ($line =~ /^\#/);                  next if ($line =~ /^\#/);
                 chomp($line);                  chomp($line);
Line 249  BEGIN { Line 248  BEGIN {
 # -------------------------------------------------------------- default domain designs  # -------------------------------------------------------------- default domain designs
     my $designdir=$Apache::lonnet::perlvar{'lonTabDir'}.'/lonDomColors';      my $designdir=$Apache::lonnet::perlvar{'lonTabDir'}.'/lonDomColors';
     my $designfile = $designdir.'/default.tab';      my $designfile = $designdir.'/default.tab';
     if ( open (my $fh,'<',$designfile) ) {      if ( open (my $fh,"<$designfile") ) {
         while (my $line = <$fh>) {          while (my $line = <$fh>) {
             next if ($line =~ /^\#/);              next if ($line =~ /^\#/);
             chomp($line);              chomp($line);
Line 263  BEGIN { Line 262  BEGIN {
     {      {
         my $categoryfile = $Apache::lonnet::perlvar{'lonTabDir'}.          my $categoryfile = $Apache::lonnet::perlvar{'lonTabDir'}.
                                   '/filecategories.tab';                                    '/filecategories.tab';
         if ( open (my $fh,'<',$categoryfile) ) {          if ( open (my $fh,"<$categoryfile") ) {
     while (my $line = <$fh>) {      while (my $line = <$fh>) {
  next if ($line =~ /^\#/);   next if ($line =~ /^\#/);
  chomp($line);   chomp($line);
                 my ($extension,$category)=(split(/\s+/,$line,2));                  my ($extension,$category)=(split(/\s+/,$line,2));
                 push(@{$category_extensions{lc($category)}},$extension);                  push @{$category_extensions{lc($category)}},$extension;
             }              }
             close($fh);              close($fh);
         }          }
Line 278  BEGIN { Line 277  BEGIN {
     {      {
         my $typesfile = $Apache::lonnet::perlvar{'lonTabDir'}.          my $typesfile = $Apache::lonnet::perlvar{'lonTabDir'}.
                '/filetypes.tab';                 '/filetypes.tab';
         if ( open (my $fh,'<',$typesfile) ) {          if ( open (my $fh,"<$typesfile") ) {
             while (my $line = <$fh>) {              while (my $line = <$fh>) {
  next if ($line =~ /^\#/);   next if ($line =~ /^\#/);
  chomp($line);   chomp($line);
Line 431  sub studentbrowser_javascript { Line 430  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,clicker,roleflag,ignorefilter,courseadv) {      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 446  sub studentbrowser_javascript { Line 445  sub studentbrowser_javascript {
                                     '&udomelement='+udom+                                      '&udomelement='+udom+
                                     '&clicker='+clicker;                                      '&clicker='+clicker;
  if (roleflag) { url+="&roles=1"; }   if (roleflag) { url+="&roles=1"; }
         if (courseadv == 'condition') {          if (courseadvonly) { url+="&courseadvonly=1"; }
             if (document.getElementById('courseadv')) {  
                 courseadv = document.getElementById('courseadv').value;  
             }  
         }  
         if ((courseadv == 'only') || (courseadv == 'none')) { url+="&courseadv="+courseadv; }  
         var title = 'Student_Browser';          var title = 'Student_Browser';
         var options = 'scrollbars=1,resizable=1,menubar=0';          var options = 'scrollbars=1,resizable=1,menubar=0';
         options += ',width=700,height=600';          options += ',width=700,height=600';
Line 483  ENDRESBRW Line 477  ENDRESBRW
 }  }
   
 sub selectstudent_link {  sub selectstudent_link {
    my ($form,$unameele,$udomele,$courseadv,$clickerid)=@_;     my ($form,$unameele,$udomele,$courseadvonly,$clickerid)=@_;
    my $callargs = "'".&Apache::lonhtmlcommon::entity_encode($form)."','".     my $callargs = "'".&Apache::lonhtmlcommon::entity_encode($form)."','".
                       &Apache::lonhtmlcommon::entity_encode($unameele)."','".                        &Apache::lonhtmlcommon::entity_encode($unameele)."','".
                       &Apache::lonhtmlcommon::entity_encode($udomele)."'";                        &Apache::lonhtmlcommon::entity_encode($udomele)."'";
Line 494  sub selectstudent_link { Line 488  sub selectstudent_link {
    return '';     return '';
        }         }
        $callargs.=",'".&Apache::lonhtmlcommon::entity_encode($clickerid)."'";         $callargs.=",'".&Apache::lonhtmlcommon::entity_encode($clickerid)."'";
        if ($courseadv eq 'only') {         if ($courseadvonly)  {
            $callargs .= ",'',1,'$courseadv'";             $callargs .= ",'',1,1";
        } elsif ($courseadv eq 'none') {  
            $callargs .= ",'','','$courseadv'";  
        } elsif ($courseadv eq 'condition') {  
            $callargs .= ",'','','$courseadv'";  
        }         }
        return '<span class="LC_nobreak">'.         return '<span class="LC_nobreak">'.
               '<a href="javascript:openstdbrowser('.$callargs.');">'.                '<a href="javascript:openstdbrowser('.$callargs.');">'.
Line 600  sub coursebrowser_javascript { Line 590  sub coursebrowser_javascript {
         if (formname == 'ccrs') {          if (formname == 'ccrs') {
             var ownername = document.forms[formid].ccuname.value;              var ownername = document.forms[formid].ccuname.value;
             var ownerdom =  document.forms[formid].ccdomain.options[document.forms[formid].ccdomain.selectedIndex].value;              var ownerdom =  document.forms[formid].ccdomain.options[document.forms[formid].ccdomain.selectedIndex].value;
             url += '&cloner='+ownername+':'+ownerdom;              url += '&cloner='+ownername+':'+ownerdom+'&crscode='+document.forms[formid].crscode.value;
             if (type == 'Course') {  
                 url += '&crscode='+document.forms[formid].crscode.value;  
             }  
         }          }
         if (formname == 'requestcrs') {          if (formname == 'requestcrs') {
             url += '&crsdom=$domainfilter&crscode=$instcode';              url += '&crsdom=$domainfilter&crscode=$instcode';
Line 690  if (!Array.prototype.indexOf) { Line 677  if (!Array.prototype.indexOf) {
         var n = 0;          var n = 0;
         if (arguments.length > 0) {          if (arguments.length > 0) {
             n = Number(arguments[1]);              n = Number(arguments[1]);
             if (n !== n) { // shortcut for verifying if it's NaN              if (n !== n) { // shortcut for verifying if it is NaN
                 n = 0;                  n = 0;
             } else if (n !== 0 && n !== (1 / 0) && n !== -(1 / 0)) {              } else if (n !== 0 && n !== (1 / 0) && n !== -(1 / 0)) {
                 n = (n > 0 || -1) * Math.floor(Math.abs(n));                  n = (n > 0 || -1) * Math.floor(Math.abs(n));
Line 926  sub check_uncheck_jscript { Line 913  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++) {
             if (!field[i].disabled) {              if (!field[i].disabled) { 
                 field[i].checked = true;                  field[i].checked = true;
             }              }
         }          }
     } else {      } else {
         if (!field.disabled) {          if (!field.disabled) { 
             field.checked = true;              field.checked = true;
         }          }
     }      }
Line 951  ENDSCRT Line 938  ENDSCRT
 }  }
   
 sub select_timezone {  sub select_timezone {
    my ($name,$selected,$onchange,$includeempty,$id,$disabled)=@_;     my ($name,$selected,$onchange,$includeempty)=@_;
    my $output='<select name="'.$name.'" '.$id.$onchange.$disabled.'>'."\n";     my $output='<select name="'.$name.'" '.$onchange.'>'."\n";
    if ($includeempty) {     if ($includeempty) {
        $output .= '<option value=""';         $output .= '<option value=""';
        if (($selected eq '') || ($selected eq 'local')) {         if (($selected eq '') || ($selected eq 'local')) {
Line 973  sub select_timezone { Line 960  sub select_timezone {
 }  }
   
 sub select_datelocale {  sub select_datelocale {
     my ($name,$selected,$onchange,$includeempty,$disabled)=@_;      my ($name,$selected,$onchange,$includeempty)=@_;
     my $output='<select name="'.$name.'" '.$onchange.$disabled.'>'."\n";      my $output='<select name="'.$name.'" '.$onchange.'>'."\n";
     if ($includeempty) {      if ($includeempty) {
         $output .= '<option value=""';          $output .= '<option value=""';
         if ($selected eq '') {          if ($selected eq '') {
Line 982  sub select_datelocale { Line 969  sub select_datelocale {
         }          }
         $output .= '> </option>';          $output .= '> </option>';
     }      }
     my @languages = &Apache::lonlocal::preferred_languages();  
     my (@possibles,%locale_names);      my (@possibles,%locale_names);
     my @locales = DateTime::Locale->ids();      my @locales = DateTime::Locale::Catalog::Locales;
     foreach my $id (@locales) {      foreach my $locale (@locales) {
         if ($id ne '') {          if (ref($locale) eq 'HASH') {
             my ($en_terr,$native_terr);              my $id = $locale->{'id'};
             my $loc = DateTime::Locale->load($id);              if ($id ne '') {
             if (ref($loc)) {                  my $en_terr = $locale->{'en_territory'};
                 $en_terr = $loc->name();                  my $native_terr = $locale->{'native_territory'};
                 $native_terr = $loc->native_name();                  my @languages = &Apache::lonlocal::preferred_languages();
                 if (grep(/^en$/,@languages) || !@languages) {                  if (grep(/^en$/,@languages) || !@languages) {
                     if ($en_terr ne '') {                      if ($en_terr ne '') {
                         $locale_names{$id} = '('.$en_terr.')';                          $locale_names{$id} = '('.$en_terr.')';
Line 1006  sub select_datelocale { Line 992  sub select_datelocale {
                     }                      }
                 }                  }
                 $locale_names{$id} = Encode::encode('UTF-8',$locale_names{$id});                  $locale_names{$id} = Encode::encode('UTF-8',$locale_names{$id});
                 push(@possibles,$id);                  push (@possibles,$id);
             }              }
         }          }
     }      }
Line 1026  sub select_datelocale { Line 1012  sub select_datelocale {
 }  }
   
 sub select_language {  sub select_language {
     my ($name,$selected,$includeempty,$noedit) = @_;      my ($name,$selected,$includeempty) = @_;
     my %langchoices;      my %langchoices;
     if ($includeempty) {      if ($includeempty) {
         %langchoices = ('' => 'No language preference');          %langchoices = ('' => 'No language preference');
Line 1038  sub select_language { Line 1024  sub select_language {
         }          }
     }      }
     %langchoices = &Apache::lonlocal::texthash(%langchoices);      %langchoices = &Apache::lonlocal::texthash(%langchoices);
     return &select_form($selected,$name,\%langchoices,undef,$noedit);      return &select_form($selected,$name,\%langchoices);
   }
   
   =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  =pod
Line 1153  sub linked_select_forms { Line 1166  sub linked_select_forms {
         $result.="select2data.d_$s1.texts = new Array(";                  $result.="select2data.d_$s1.texts = new Array(";        
         my @s2texts;          my @s2texts;
         foreach my $value (@s2values) {          foreach my $value (@s2values) {
             push(@s2texts, $hashref->{$s1}->{'select2'}->{$value});              push @s2texts, $hashref->{$s1}->{'select2'}->{$value};
         }          }
         $result.="\"@s2texts\");\n";          $result.="\"@s2texts\");\n";
     }      }
Line 1222  END Line 1235  END
   
 =pod  =pod
   
 =item * &help_open_topic($topic,$text,$stayOnPage,$width,$height,$imgid,$links_target)  =item * &help_open_topic($topic,$text,$stayOnPage,$width,$height,$imgid)
   
 Returns a string corresponding to an HTML link to the given help  Returns a string corresponding to an HTML link to the given help
 $topic, where $topic corresponds to the name of a .tex file in  $topic, where $topic corresponds to the name of a .tex file in
Line 1246  $imgid is the id of the img tag used for Line 1259  $imgid is the id of the img tag used for
 used in a javascript call to switch the image src.  See   used in a javascript call to switch the image src.  See 
 lonhtmlcommon::htmlareaselectactive() for an example.  lonhtmlcommon::htmlareaselectactive() for an example.
   
 $links_target will optionally be set to a target (_top, _parent or _self).  
   
 =cut  =cut
   
 sub help_open_topic {  sub help_open_topic {
     my ($topic, $text, $stayOnPage, $width, $height, $imgid, $links_target) = @_;      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 = 500 if (not defined $width);      $width = 500 if (not defined $width);
Line 1265  sub help_open_topic { Line 1276  sub help_open_topic {
     $topic=~s/\W/\_/g;      $topic=~s/\W/\_/g;
   
     if (!$stayOnPage) {      if (!$stayOnPage) {
         if ($env{'browser.mobile'}) {   $link = "javascript:openMyModal('/adm/help/${filename}.hlp',$width,$height,'yes');";
     $link = "javascript:openMyModal('/adm/help/${filename}.hlp',$width,$height,'yes');";  
         } else {  
             $link = "javascript:void(open('/adm/help/${filename}.hlp', 'Help_for_$topic', 'menubar=0,toolbar=1,scrollbars=1,width=$width,height=$height,resizable=yes'))";  
         }  
     } elsif ($stayOnPage eq 'popup') {      } 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'))";          $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 {
Line 1277  sub help_open_topic { Line 1284  sub help_open_topic {
     }      }
   
     # Add the text      # Add the text
     my $target = ' target="_top"';  
     if ($links_target) {  
         $target = ' target="'.$links_target.'"';  
     } elsif (($env{'request.deeplink.login'}) && ($env{'request.deeplink.target'} eq '_self')) {  
         $target = '';  
     }  
     if ($text ne "") {      if ($text ne "") {
  $template.='<span class="LC_help_open_topic">'   $template.='<span class="LC_help_open_topic">'
                   .'<a'.$target.' href="'.$link.'">'                    .'<a target="_top" href="'.$link.'">'
                   .$text.'</a>';                    .$text.'</a>';
     }      }
   
Line 1295  sub help_open_topic { Line 1296  sub help_open_topic {
     if ($imgid ne '') {      if ($imgid ne '') {
         $imgid = ' id="'.$imgid.'"';          $imgid = ' id="'.$imgid.'"';
     }      }
     $template.=' <a'.$target.' 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 
Line 1324  sub helpLatexCheatsheet { Line 1325  sub helpLatexCheatsheet {
   .&help_open_topic('Other_Symbols',&mt('Other Symbols'),$stayOnPage,undef,600)    .&help_open_topic('Other_Symbols',&mt('Other Symbols'),$stayOnPage,undef,600)
   .'</span>';    .'</span>';
     unless ($not_author) {      unless ($not_author) {
         $out .= ' <span>'          $out .= '<span>'
        .&help_open_topic('Authoring_Output_Tags',&mt('Output Tags'),$stayOnPage,undef,600)                 .&help_open_topic('Authoring_Output_Tags',&mt('Output Tags'),$stayOnPage,undef,600)
        .'</span> <span>'                 .'</span> <span>'
                .&help_open_topic('Authoring_Multilingual_Problems',&mt('Languages'),$stayOnPage,undef,600)                 .&help_open_topic('Authoring_Multilingual_Problems',&mt('How to create problems in different languages'),$stayOnPage,undef,600)
                .'</span>';         .'</span>';
     }      }
     $out .= '</span>'; # End cheatsheet      $out .= '</span>'; # End cheatsheet
     return $out;      return $out;
Line 1368  ENDOUTPUT Line 1369  ENDOUTPUT
   
 # now just updates the help link and generates a blue icon  # now just updates the help link and generates a blue icon
 sub help_open_menu {  sub help_open_menu {
     my ($topic,$component_help,$faq,$bug,$stayOnPage,$width,$height,$text,$links_target)       my ($topic,$component_help,$faq,$bug,$stayOnPage,$width,$height,$text) 
  = @_;       = @_;    
     $stayOnPage = 1;      $stayOnPage = 1;
     my $output;      my $output;
     if ($component_help) {      if ($component_help) {
  if (!$text) {   if (!$text) {
     $output=&help_open_topic($component_help,undef,$stayOnPage,      $output=&help_open_topic($component_help,undef,$stayOnPage,
        $width,$height,'',$links_target);         $width,$height);
  } else {   } else {
     my $help_text;      my $help_text;
     $help_text=&unescape($topic);      $help_text=&unescape($topic);
     $output='<table><tr><td>'.      $output='<table><tr><td>'.
  &help_open_topic($component_help,$help_text,$stayOnPage,   &help_open_topic($component_help,$help_text,$stayOnPage,
  $width,$height,'',$links_target).'</td></tr></table>';   $width,$height).'</td></tr></table>';
  }   }
     }      }
     my $banner_link = &update_help_link($topic,$component_help,$faq,$bug,$stayOnPage);      my $banner_link = &update_help_link($topic,$component_help,$faq,$bug,$stayOnPage);
Line 1389  sub help_open_menu { Line 1390  sub help_open_menu {
 }  }
   
 sub top_nav_help {  sub top_nav_help {
     my ($text,$linkattr) = @_;      my ($text) = @_;
     $text = &mt($text);      $text = &mt($text);
     my $stay_on_page;      my $stay_on_page = 1;
     unless ($env{'environment.remote'} eq 'on') {  
         $stay_on_page = 1;  
     }  
     my ($link,$banner_link);      my ($link,$banner_link);
     unless ($env{'request.noversionuri'} =~ m{^/adm/helpmenu}) {      unless ($env{'request.noversionuri'} =~ m{^/adm/helpmenu}) {
         $link = ($stay_on_page) ? "javascript:helpMenu('display')"          $link = ($stay_on_page) ? "javascript:helpMenu('display')"
Line 1405  sub top_nav_help { Line 1404  sub top_nav_help {
     if ($link) {      if ($link) {
         return <<"END";          return <<"END";
 $banner_link  $banner_link
 <a href="$link" title="$title" $linkattr>$text</a>  <a href="$link" title="$title">$text</a>
 END  END
     } else {      } else {
         return '&nbsp;'.$text.'&nbsp;';          return '&nbsp;'.$text.'&nbsp;';
Line 1426  sub help_menu_js { Line 1425  sub help_menu_js {
  'js_ready'    => 1,   'js_ready'    => 1,
                                         'use_absolute' => $httphost,                                          'use_absolute' => $httphost,
  'add_entries' => {   'add_entries' => {
     'border' => '0',      'border' => '0', 
     'rows'   => "110,*",},});      'rows'   => "110,*",},});
     my $end_page =      my $end_page =
         &Apache::loncommon::end_page({'frameset' => 1,          &Apache::loncommon::end_page({'frameset' => 1,
Line 1490  sub help_open_bug { Line 1489  sub help_open_bug {
     {      {
  $link = $url;   $link = $url;
     }      }
   
     my $target = '_top';  
     if ((($env{'request.lti.login'}) && ($env{'request.lti.target'} eq 'iframe')) ||  
         (($env{'request.deeplink.login'}) && ($env{'request.deeplink.target'} eq '_self'))) {  
         $target = '_blank';  
     }  
   
     # Add the text      # Add the text
     if ($text ne "")      if ($text ne "")
     {      {
  $template .=    $template .= 
   "<table bgcolor='#AA3333' cellspacing='1' cellpadding='1' border='0'><tr>".    "<table bgcolor='#AA3333' cellspacing='1' cellpadding='1' border='0'><tr>".
   "<td bgcolor='#FF5555'><a target=\"$target\" href=\"$link\"><span style=\"color:#FFFFFF;font-size:10pt;\">$text</span></a>";    "<td bgcolor='#FF5555'><a target=\"_top\" href=\"$link\"><span style=\"color:#FFFFFF;font-size:10pt;\">$text</span></a>";
     }      }
   
     # Add the graphic      # Add the graphic
     my $title = &mt('Report a Bug');      my $title = &mt('Report a Bug');
     my $bugicon=&lonhttpdurl("/adm/lonMisc/smallBug.gif");      my $bugicon=&lonhttpdurl("/adm/lonMisc/smallBug.gif");
     $template .= <<"ENDTEMPLATE";      $template .= <<"ENDTEMPLATE";
  <a target="$target" href="$link" title="$title"><img src="$bugicon" border="0" alt="(Bug: $topic)" /></a>   <a target="_top" href="$link" title="$title"><img src="$bugicon" border="0" alt="(Bug: $topic)" /></a>
 ENDTEMPLATE  ENDTEMPLATE
     if ($text ne '') { $template.='</td></tr></table>' };      if ($text ne '') { $template.='</td></tr></table>' };
     return $template;      return $template;
Line 1820  sub colorfuleditor_js { Line 1812  sub colorfuleditor_js {
             }              }
   
             // only iterate whole storage if nothing to override              // only iterate whole storage if nothing to override
             if(localStorage.getItem(key) == null){              if(localStorage.getItem(key) == null){        
   
                 // prevent storage from growing large                  // prevent storage from growing large
                 if(localStorage.length > 50){                  if(localStorage.length > 50){
                     var regex_getTimestamp = /^(?:\d)+;/;                      var regex_getTimestamp = /^(?:\d)+;/;
                     var oldest_timestamp = regex_getTimestamp.exec(localStorage.key(0));                      var oldest_timestamp = regex_getTimestamp.exec(localStorage.key(0));
                     var oldest_key;                      var oldest_key;
                       
                     for(var i = 1; i < localStorage.length; i++){                      for(var i = 1; i < localStorage.length; i++){
                         if (regex_getTimestamp.exec(localStorage.key(i)) < oldest_timestamp) {                          if (regex_getTimestamp.exec(localStorage.key(i)) < oldest_timestamp) {
                             oldest_key = localStorage.key(i);                              oldest_key = localStorage.key(i);
Line 1857  sub colorfuleditor_js { Line 1849  sub colorfuleditor_js {
                 pairs = valueArr[i].split(',');                  pairs = valueArr[i].split(',');
                 elements = document.getElementsByName(pairs[0]);                  elements = document.getElementsByName(pairs[0]);
   
                 for (var j = 0; j < elements.length; j++){                  for (var j = 0; j < elements.length; j++){  
                     elements[j].style.display = pairs[1];                      elements[j].style.display = pairs[1];
                     if (pairs[1] == "none"){                      if (pairs[1] == "none"){
                         var regex_id = /([_\\d]+)\$/;                          var regex_id = /([_\\d]+)\$/;
Line 1870  sub colorfuleditor_js { Line 1862  sub colorfuleditor_js {
     }      }
   
     function getTagList () {      function getTagList () {
           
         var stringToSearch = document.lonhomework.innerHTML;          var stringToSearch = document.lonhomework.innerHTML;
   
         var ret = new Array();          var ret = new Array();
Line 1878  sub colorfuleditor_js { Line 1870  sub colorfuleditor_js {
         var tag_list = stringToSearch.match(regex_findBlock);          var tag_list = stringToSearch.match(regex_findBlock);
   
         if(tag_list != null){          if(tag_list != null){
             for(var i = 0; i < tag_list.length; i++){              for(var i = 0; i < tag_list.length; i++){            
                 ret.push(tag_list[i].replace(/"/, ''));                  ret.push(tag_list[i].replace(/"/, ''));
             }              }
         }          }
Line 1915  sub colorfuleditor_js { Line 1907  sub colorfuleditor_js {
   
             for(var i = 0; i < tag_list.length; i++){              for(var i = 0; i < tag_list.length; i++){
                 elem_list = document.getElementsByName(tag_list[i]);                  elem_list = document.getElementsByName(tag_list[i]);
                   
                 if(elem_list.length > 0){                  if(elem_list.length > 0){
                     elem = elem_list[0];                      elem = elem_list[0];
                     break;                      break;
Line 1938  sub colorfuleditor_js { Line 1930  sub colorfuleditor_js {
             rect.right <= (window.innerWidth || document.documentElement.clientWidth) /*or $(window).width() */              rect.right <= (window.innerWidth || document.documentElement.clientWidth) /*or $(window).width() */
         );          );
     }      }
       
     function autosize(depth){      function autosize(depth){
         var cmInst = window['cm'+depth];          var cmInst = window['cm'+depth];
         var fitsizeButton = document.getElementById('fitsize'+depth);          var fitsizeButton = document.getElementById('fitsize'+depth);
Line 2005  sub insert_folding_button { Line 1997  sub insert_folding_button {
     my $curDepth = $Apache::lonxml::curdepth;      my $curDepth = $Apache::lonxml::curdepth;
     my $lastresource = $env{'request.ambiguous'};      my $lastresource = $env{'request.ambiguous'};
   
     return "<input type=\"button\" id=\"folding_btn_$curDepth\"      return "<input type=\"button\" id=\"folding_btn_$curDepth\" 
             value=\"".&mt('Hide')."\" onclick=\"fold_box('$curDepth','$lastresource')\">";              value=\"".&mt('Hide')."\" onclick=\"fold_box('$curDepth','$lastresource')\">";
 }  }
   
   
 =pod  =pod
   
 =head1 Excel and CSV file utility routines  =head1 Excel and CSV file utility routines
Line 2269  sub multiple_select_form { Line 2260  sub multiple_select_form {
   
 =pod  =pod
   
 =item * &select_form($defdom,$name,$hashref,$onchange,$readonly)  =item * &select_form($defdom,$name,$hashref,$onchange)
   
 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();"  
 An optional arg -- $readonly -- if true will cause the select form  
 to be disabled, e.g., for the case where an instructor has a section-  
 specific role, and is viewing/modifying parameters.    
   
 See lonrights.pm for an example invocation and use.  See lonrights.pm for an example invocation and use.
   
Line 2463  sub select_level_form { Line 2451  sub select_level_form {
   
 =pod  =pod
   
 =item * &select_dom_form($defdom,$name,$includeempty,$showdomdesc,$onchange,$incdoms,$excdoms,$disabled)  =item * &select_dom_form($defdom,$name,$includeempty,$showdomdesc,$onchange,$incdoms,$excdoms)
   
 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 the domain to preform an operation in.    allow a user to select the domain to preform an operation in.  
Line 2480  The optional $incdoms is a reference to Line 2468  The optional $incdoms is a reference to
   
 The optional $excdoms is a reference to an array of domains which will be excluded from the available options.  The optional $excdoms is a reference to an array of domains which will be excluded from the available options.
   
 The optional $disabled argument, if true, adds the disabled attribute to the select tag.   
   
 =cut  =cut
   
 #-------------------------------------------  #-------------------------------------------
 sub select_dom_form {  sub select_dom_form {
     my ($defdom,$name,$includeempty,$showdomdesc,$onchange,$incdoms,$excdoms,$disabled) = @_;      my ($defdom,$name,$includeempty,$showdomdesc,$onchange,$incdoms,$excdoms) = @_;
     if ($onchange) {      if ($onchange) {
         $onchange = ' onchange="'.$onchange.'"';          $onchange = ' onchange="'.$onchange.'"';
     }      }
     if ($disabled) {  
         $disabled = ' disabled="disabled"';  
     }  
     my (@domains,%exclude);      my (@domains,%exclude);
     if (ref($incdoms) eq 'ARRAY') {      if (ref($incdoms) eq 'ARRAY') {
         @domains = sort {lc($a) cmp lc($b)} (@{$incdoms});          @domains = sort {lc($a) cmp lc($b)} (@{$incdoms});
Line 2501  sub select_dom_form { Line 2484  sub select_dom_form {
     }      }
     if ($includeempty) { @domains=('',@domains); }      if ($includeempty) { @domains=('',@domains); }
     if (ref($excdoms) eq 'ARRAY') {      if (ref($excdoms) eq 'ARRAY') {
         map { $exclude{$_} = 1; } @{$excdoms};          map { $exclude{$_} = 1; } @{$excdoms}; 
     }      }
     my $selectdomain = "<select name=\"$name\" size=\"1\"$onchange$disabled>\n";      my $selectdomain = "<select name=\"$name\" size=\"1\"$onchange>\n";
     foreach my $dom (@domains) {      foreach my $dom (@domains) {
         next if ($exclude{$dom});          next if ($exclude{$dom});
         $selectdomain.="<option value=\"$dom\" ".          $selectdomain.="<option value=\"$dom\" ".
Line 2857  sub authform_nochange { Line 2840  sub authform_nochange {
               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 (!$authnum) {      if (!$authnum) {
         $result = &mt('Under your 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');
Line 2879  sub authform_kerberos { Line 2862  sub authform_kerberos {
               @_,                @_,
               );                );
     my ($check4,$check5,$krbcheck,$krbarg,$krbver,$result,$authtype,      my ($check4,$check5,$krbcheck,$krbarg,$krbver,$result,$authtype,
         $autharg,$jscall,$disabled);          $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 {
        $check4 = ' checked="checked"';         $check4 = ' checked="checked"';
     }      }
     if ($in{'readonly'}) {  
         $disabled = ' disabled="disabled"';  
     }  
     $krbarg = $in{'kerb_def_dom'};      $krbarg = $in{'kerb_def_dom'};
     if (defined($in{'curr_authtype'})) {      if (defined($in{'curr_authtype'})) {
         if ($in{'curr_authtype'} eq 'krb') {          if ($in{'curr_authtype'} eq 'krb') {
Line 2933  sub authform_kerberos { Line 2913  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="radio" name="login" value="krb"'.$disabled.' />';                      $authtype = '<input type="radio" name="login" value="krb" />';
                 }                  }
             }              }
         }          }
Line 2942  sub authform_kerberos { Line 2922  sub authform_kerberos {
     if ($authtype eq '') {      if ($authtype eq '') {
         $authtype = '<input type="radio" name="login" value="krb" '.          $authtype = '<input type="radio" name="login" value="krb" '.
                     'onclick="'.$jscall.'" onchange="'.$jscall.'"'.                      'onclick="'.$jscall.'" onchange="'.$jscall.'"'.
                     $krbcheck.$disabled.' />';                      $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'} &&
Line 2955  sub authform_kerberos { Line 2935  sub authform_kerberos {
          '<label>'.$authtype,           '<label>'.$authtype,
          '</label><input type="text" size="10" name="krbarg" '.           '</label><input type="text" size="10" name="krbarg" '.
              'value="'.$krbarg.'" '.               'value="'.$krbarg.'" '.
              'onchange="'.$jscall.'"'.$disabled.' />',               'onchange="'.$jscall.'" />',
          '<label><input type="radio" name="krbver" value="4" '.$check4.$disabled.' />',           '<label><input type="radio" name="krbver" value="4" '.$check4.' />',
          '</label><label><input type="radio" name="krbver" value="5" '.$check5.$disabled.' />',           '</label><label><input type="radio" name="krbver" value="5" '.$check5.' />',
  '</label>');   '</label>');
     } elsif ($can_assign{'krb4'}) {      } elsif ($can_assign{'krb4'}) {
         $result .= &mt          $result .= &mt
Line 2966  sub authform_kerberos { Line 2946  sub authform_kerberos {
          '<label>'.$authtype,           '<label>'.$authtype,
          '</label><input type="text" size="10" name="krbarg" '.           '</label><input type="text" size="10" name="krbarg" '.
              'value="'.$krbarg.'" '.               'value="'.$krbarg.'" '.
              'onchange="'.$jscall.'"'.$disabled.' />',               'onchange="'.$jscall.'" />',
          '<label><input type="hidden" name="krbver" value="4" />',           '<label><input type="hidden" name="krbver" value="4" />',
          '</label>');           '</label>');
     } elsif ($can_assign{'krb5'}) {      } elsif ($can_assign{'krb5'}) {
Line 2976  sub authform_kerberos { Line 2956  sub authform_kerberos {
          '<label>'.$authtype,           '<label>'.$authtype,
          '</label><input type="text" size="10" name="krbarg" '.           '</label><input type="text" size="10" name="krbarg" '.
              'value="'.$krbarg.'" '.               'value="'.$krbarg.'" '.
              'onchange="'.$jscall.'"'.$disabled.' />',               'onchange="'.$jscall.'" />',
          '<label><input type="hidden" name="krbver" value="5" />',           '<label><input type="hidden" name="krbver" value="5" />',
          '</label>');           '</label>');
     }      }
Line 2989  sub authform_internal { Line 2969  sub authform_internal {
                 kerb_def_dom => 'MSU.EDU',                  kerb_def_dom => 'MSU.EDU',
                 @_,                  @_,
                 );                  );
     my ($intcheck,$intarg,$result,$authtype,$autharg,$jscall,$disabled);      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 ($in{'readonly'}) {  
         $disabled = ' disabled="disabled"';  
     }  
     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 3022  sub authform_internal { Line 2999  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="radio" name="login" value="int"'.$disabled.' />';                      $authtype = '<input type="radio" name="login" value="int" />';
                 }                  }
             }              }
         }          }
Line 3030  sub authform_internal { Line 3007  sub authform_internal {
     $jscall = "javascript:changed_radio('int',$in{'formname'});";      $jscall = "javascript:changed_radio('int',$in{'formname'});";
     if ($authtype eq '') {      if ($authtype eq '') {
         $authtype = '<input type="radio" name="login" value="int" '.$intcheck.          $authtype = '<input type="radio" name="login" value="int" '.$intcheck.
                     ' onchange="'.$jscall.'" onclick="'.$jscall.'"'.$disabled.' />';                      ' onchange="'.$jscall.'" onclick="'.$jscall.'" />';
     }      }
     $autharg = '<input type="password" size="10" name="intarg" value="'.      $autharg = '<input type="password" size="10" name="intarg" value="'.
                $intarg.'" onchange="'.$jscall.'"'.$disabled.' />';                 $intarg.'" onchange="'.$jscall.'" />';
     $result = &mt      $result = &mt
         ('[_1] Internally authenticated (with initial password [_2])',          ('[_1] Internally authenticated (with initial password [_2])',
          '<label>'.$authtype,'</label>'.$autharg);           '<label>'.$authtype,'</label>'.$autharg);
     $result.='<label><input type="checkbox" name="visible" onclick="if (this.checked) { this.form.intarg.type='."'text'".' } else { this.form.intarg.type='."'password'".' }"'.$disabled.' />'.&mt('Visible input').'</label>';      $result.="<label><input type=\"checkbox\" name=\"visible\" onclick='if (this.checked) { this.form.intarg.type=\"text\" } else { this.form.intarg.type=\"password\" }' />".&mt('Visible input').'</label>';
     return $result;      return $result;
 }  }
   
Line 3047  sub authform_local { Line 3024  sub authform_local {
               kerb_def_dom => 'MSU.EDU',                kerb_def_dom => 'MSU.EDU',
               @_,                @_,
               );                );
     my ($loccheck,$locarg,$result,$authtype,$autharg,$jscall,$disabled);      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 ($in{'readonly'}) {  
         $disabled = ' disabled="disabled"';  
     }  
     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 3080  sub authform_local { Line 3054  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="radio" name="login" value="loc"'.$disabled.' />';                      $authtype = '<input type="radio" name="login" value="loc" />';
                 }                  }
             }              }
         }          }
Line 3089  sub authform_local { Line 3063  sub authform_local {
     if ($authtype eq '') {      if ($authtype eq '') {
         $authtype = '<input type="radio" name="login" value="loc" '.          $authtype = '<input type="radio" name="login" value="loc" '.
                     $loccheck.' onchange="'.$jscall.'" onclick="'.                      $loccheck.' onchange="'.$jscall.'" onclick="'.
                     $jscall.'"'.$disabled.' />';                      $jscall.'" />';
     }      }
     $autharg = '<input type="text" size="10" name="locarg" value="'.      $autharg = '<input type="text" size="10" name="locarg" value="'.
                $locarg.'" onchange="'.$jscall.'"'.$disabled.' />';                 $locarg.'" onchange="'.$jscall.'" />';
     $result = &mt('[_1] Local Authentication with argument [_2]',      $result = &mt('[_1] Local Authentication with argument [_2]',
                   '<label>'.$authtype,'</label>'.$autharg);                    '<label>'.$authtype,'</label>'.$autharg);
     return $result;      return $result;
Line 3104  sub authform_filesystem { Line 3078  sub authform_filesystem {
               kerb_def_dom => 'MSU.EDU',                kerb_def_dom => 'MSU.EDU',
               @_,                @_,
               );                );
     my ($fsyscheck,$result,$authtype,$autharg,$jscall,$disabled);      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 ($in{'readonly'}) {  
         $disabled = ' disabled="disabled"';  
     }  
     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 3134  sub authform_filesystem { Line 3105  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="radio" name="login" value="fsys"'.$disabled.' />';                      $authtype = '<input type="radio" name="login" value="fsys" />';
                 }                  }
             }              }
         }          }
Line 3143  sub authform_filesystem { Line 3114  sub authform_filesystem {
     if ($authtype eq '') {      if ($authtype eq '') {
         $authtype = '<input type="radio" name="login" value="fsys" '.          $authtype = '<input type="radio" name="login" value="fsys" '.
                     $fsyscheck.' onchange="'.$jscall.'" onclick="'.                      $fsyscheck.' onchange="'.$jscall.'" onclick="'.
                     $jscall.'"'.$disabled.' />';                      $jscall.'" />';
     }      }
     $autharg = '<input type="password" size="10" name="fsysarg" value=""'.      $autharg = '<input type="text" size="10" name="fsysarg" value=""'.
                ' onchange="'.$jscall.'"'.$disabled.' />';                 ' onchange="'.$jscall.'" />';
     $result = &mt      $result = &mt
         ('[_1] Filesystem Authenticated (with initial password [_2])',          ('[_1] Filesystem Authenticated (with initial password [_2])',
          '<label>'.$authtype,'</label>'.$autharg);           '<label><input type="radio" name="login" value="fsys" '.
            $fsyscheck.'onchange="'.$jscall.'" onclick="'.$jscall.'" />',
            '</label><input type="password" size="10" name="fsysarg" value="" '.
                     'onchange="'.$jscall.'" />');
     return $result;      return $result;
 }  }
   
Line 3171  sub get_assignable_auth { Line 3145  sub get_assignable_auth {
             my $context;              my $context;
             if ($env{'request.role'} =~ /^au/) {              if ($env{'request.role'} =~ /^au/) {
                 $context = 'author';                  $context = 'author';
             } elsif ($env{'request.role'} =~ /^(dc|dh)/) {              } elsif ($env{'request.role'} =~ /^dc/) {
                 $context = 'domain';                  $context = 'domain';
             } elsif ($env{'request.course.id'}) {              } elsif ($env{'request.course.id'}) {
                 $context = 'course';                  $context = 'course';
Line 3195  sub get_assignable_auth { Line 3169  sub get_assignable_auth {
     return ($authnum,%can_assign);      return ($authnum,%can_assign);
 }  }
   
 sub check_passwd_rules {  
     my ($domain,$plainpass) = @_;  
     my %passwdconf = &Apache::lonnet::get_passwdconf($domain);  
     my ($min,$max,@chars,@brokerule,$warning);  
     $min = $Apache::lonnet::passwdmin;  
     if (ref($passwdconf{'chars'}) eq 'ARRAY') {  
         if ($passwdconf{'min'} =~ /^\d+$/) {  
             if ($passwdconf{'min'} > $min) {  
                 $min = $passwdconf{'min'};  
             }  
         }  
         if ($passwdconf{'max'} =~ /^\d+$/) {  
             $max = $passwdconf{'max'};  
         }  
         @chars = @{$passwdconf{'chars'}};  
     }  
     if (($min) && (length($plainpass) < $min)) {  
         push(@brokerule,'min');  
     }  
     if (($max) && (length($plainpass) > $max)) {  
         push(@brokerule,'max');  
     }  
     if (@chars) {  
         my %rules;  
         map { $rules{$_} = 1; } @chars;  
         if ($rules{'uc'}) {  
             unless ($plainpass =~ /[A-Z]/) {  
                 push(@brokerule,'uc');  
             }  
         }  
         if ($rules{'lc'}) {  
             unless ($plainpass =~ /[a-z]/) {  
                 push(@brokerule,'lc');  
             }  
         }  
         if ($rules{'num'}) {  
             unless ($plainpass =~ /\d/) {  
                 push(@brokerule,'num');  
             }  
         }  
         if ($rules{'spec'}) {  
             unless ($plainpass =~ /[!"#$%&'()*+,\-.\/:;<=>?@[\\\]^_`{|}~]/) {  
                 push(@brokerule,'spec');  
             }  
         }  
     }  
     if (@brokerule) {  
         my %rulenames = &Apache::lonlocal::texthash(  
             uc   => 'At least one upper case letter',  
             lc   => 'At least one lower case letter',  
             num  => 'At least one number',  
             spec => 'At least one non-alphanumeric',  
         );  
         $rulenames{'uc'} .= ': ABCDEFGHIJKLMNOPQRSTUVWXYZ';  
         $rulenames{'lc'} .= ': abcdefghijklmnopqrstuvwxyz';  
         $rulenames{'num'} .= ': 0123456789';  
         $rulenames{'spec'} .= ': !&quot;\#$%&amp;\'()*+,-./:;&lt;=&gt;?@[\]^_\`{|}~';  
         $rulenames{'min'} = &mt('Minimum password length: [_1]',$min);  
         $rulenames{'max'} = &mt('Maximum password length: [_1]',$max);  
         $warning = &mt('Password did not satisfy the following:').'<ul>';  
         foreach my $rule ('min','max','uc','lc','num','spec') {  
             if (grep(/^$rule$/,@brokerule)) {  
                 $warning .= '<li>'.$rulenames{$rule}.'</li>';  
             }  
         }  
         $warning .= '</ul>';  
     }  
     if (wantarray) {  
         return @brokerule;  
     }  
     return $warning;  
 }  
   
 sub passwd_validation_js {  
     my ($currpasswdval,$domain,$context,$id) = @_;  
     my (%passwdconf,$alertmsg);  
     if ($context eq 'linkprot') {  
         my %domconfig = &Apache::lonnet::get_dom('configuration',['ltisec'],$domain);  
         if (ref($domconfig{'ltisec'}) eq 'HASH') {  
             if (ref($domconfig{'ltisec'}{'rules'}) eq 'HASH') {  
                 %passwdconf = %{$domconfig{'ltisec'}{'rules'}};  
             }  
         }  
         if ($id eq 'add') {  
             $alertmsg = &mt('Secret for added launcher did not satisfy requirement(s):').'\n\n';  
         } elsif ($id =~ /^\d+$/) {  
             my $pos = $id+1;  
             $alertmsg = &mt('Secret for launcher [_1] did not satisfy requirement(s):','#'.$pos).'\n\n';  
         } else {  
             $alertmsg = &mt('A secret did not satisfy requirement(s):').'\n\n';  
         }  
     } else {  
         %passwdconf = &Apache::lonnet::get_passwdconf($domain);  
         $alertmsg = &mt('Initial password did not satisfy requirement(s):').'\n\n';  
     }  
     my ($min,$max,@chars,$numrules,$intargjs,%alert);  
     $numrules = 0;  
     $min = $Apache::lonnet::passwdmin;  
     if (ref($passwdconf{'chars'}) eq 'ARRAY') {  
         if ($passwdconf{'min'} =~ /^\d+$/) {  
             if ($passwdconf{'min'} > $min) {  
                 $min = $passwdconf{'min'};  
             }  
         }  
         if ($passwdconf{'max'} =~ /^\d+$/) {  
             $max = $passwdconf{'max'};  
             $numrules ++;  
         }  
         @chars = @{$passwdconf{'chars'}};  
         if (@chars) {  
             $numrules ++;  
         }  
     }  
     if ($min > 0) {  
         $numrules ++;  
     }  
     if (($min > 0) || ($max ne '') || (@chars > 0)) {  
         if ($min) {  
             $alert{'min'} = &mt('minimum [quant,_1,character]',$min).'\n';  
         }  
         if ($max) {  
             $alert{'max'} = &mt('maximum [quant,_1,character]',$max).'\n';  
         }  
         my (@charalerts,@charrules);  
         if (@chars) {  
             if (grep(/^uc$/,@chars)) {  
                 push(@charalerts,&mt('contain at least one upper case letter'));  
                 push(@charrules,'uc');  
             }  
             if (grep(/^lc$/,@chars)) {  
                 push(@charalerts,&mt('contain at least one lower case letter'));  
                 push(@charrules,'lc');  
             }  
             if (grep(/^num$/,@chars)) {  
                 push(@charalerts,&mt('contain at least one number'));  
                 push(@charrules,'num');  
             }  
             if (grep(/^spec$/,@chars)) {  
                 push(@charalerts,&mt('contain at least one non-alphanumeric'));  
                 push(@charrules,'spec');  
             }  
         }  
         $intargjs = qq|            var rulesmsg = '';\n|.  
                     qq|            var currpwval = $currpasswdval;\n|;  
             if ($min) {  
                 $intargjs .= qq|  
             if (currpwval.length < $min) {  
                 rulesmsg += ' - $alert{min}';  
             }  
 |;  
             }  
             if ($max) {  
                 $intargjs .= qq|  
             if (currpwval.length > $max) {  
                 rulesmsg += ' - $alert{max}';  
             }  
 |;  
             }  
             if (@chars > 0) {  
                 my $charrulestr = '"'.join('","',@charrules).'"';  
                 my $charalertstr = '"'.join('","',@charalerts).'"';  
                 $intargjs .= qq|            var brokerules = new Array();\n|.  
                              qq|            var charrules = new Array($charrulestr);\n|.  
                              qq|            var charalerts = new Array($charalertstr);\n|;  
                 my %rules;  
                 map { $rules{$_} = 1; } @chars;  
                 if ($rules{'uc'}) {  
                     $intargjs .= qq|  
             var ucRegExp = /[A-Z]/;  
             if (!ucRegExp.test(currpwval)) {  
                 brokerules.push('uc');  
             }  
 |;  
                 }  
                 if ($rules{'lc'}) {  
                     $intargjs .= qq|  
             var lcRegExp = /[a-z]/;  
             if (!lcRegExp.test(currpwval)) {  
                 brokerules.push('lc');  
             }  
 |;  
                 }  
                 if ($rules{'num'}) {  
                      $intargjs .= qq|  
             var numRegExp = /[0-9]/;  
             if (!numRegExp.test(currpwval)) {  
                 brokerules.push('num');  
             }  
 |;  
                 }  
                 if ($rules{'spec'}) {  
                      $intargjs .= q|  
             var specRegExp = /[!"#$%&'()*+,\-.\/:;<=>?@[\\^\]_`{\|}~]/;  
             if (!specRegExp.test(currpwval)) {  
                 brokerules.push('spec');  
             }  
 |;  
                 }  
                 $intargjs .= qq|  
             if (brokerules.length > 0) {  
                 for (var i=0; i<brokerules.length; i++) {  
                     for (var j=0; j<charrules.length; j++) {  
                         if (brokerules[i] == charrules[j]) {  
                             rulesmsg += ' - '+charalerts[j]+'\\n';  
                             break;  
                         }  
                     }  
                 }  
             }  
 |;  
             }  
             $intargjs .= qq|  
             if (rulesmsg != '') {  
                 rulesmsg = '$alertmsg'+rulesmsg;  
                 alert(rulesmsg);  
                 return false;  
             }  
 |;  
     }  
     return ($numrules,$intargjs);  
 }  
   
 ###############################################################  ###############################################################
 ##    Get Kerberos Defaults for Domain                 ##  ##    Get Kerberos Defaults for Domain                 ##
 ###############################################################  ###############################################################
Line 3584  sub get_related_words { Line 3336  sub get_related_words {
     untie %thesaurus_db;      untie %thesaurus_db;
     return @Words;      return @Words;
 }  }
   ###############################################################
   #
   #  Spell checking
   #
   
 =pod  =pod
   
 =back  =back
   
   =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  =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 3835  sub syllabuswrapper { Line 3647  sub syllabuswrapper {
     return qq{<a href="/public/$domain/$coursedir/syllabus">$linktext</a>};      return qq{<a href="/public/$domain/$coursedir/syllabus">$linktext</a>};
 }  }
   
 sub aboutme_on {  
     my ($uname,$udom)=@_;  
     unless ($uname) { $uname=$env{'user.name'}; }  
     unless ($udom)  { $udom=$env{'user.domain'}; }  
     return if ($udom eq 'public' && $uname eq 'public');  
     my $hashkey=$uname.':'.$udom;  
     my ($aboutme,$cached)=&Apache::lonnet::is_cached_new('aboutme',$hashkey);  
     if ($cached) {  
         return $aboutme;  
     }  
     $aboutme = &Apache::lonnet::usertools_access($uname,$udom,'aboutme');  
     &Apache::lonnet::do_cache_new('aboutme',$hashkey,$aboutme,3600);  
     return $aboutme;  
 }  
   
 sub devalidate_aboutme_cache {  
     my ($uname,$udom)=@_;  
     if (!$udom)  { $udom =$env{'user.domain'}; }  
     if (!$uname) { $uname=$env{'user.name'};   }  
     return if ($udom eq 'public' && $uname eq 'public');  
     my $id=$uname.':'.$udom;  
     &Apache::lonnet::devalidate_cache_new('aboutme',$id);  
 }  
   
 # -----------------------------------------------------------------------------  # -----------------------------------------------------------------------------
   
 sub track_student_link {  sub track_student_link {
Line 4245  Return string with previous attempt on p Line 4033  Return string with previous attempt on p
   
 =item * $usec: section of the desired student  =item * $usec: section of the desired student
   
 =item * $identifier: counter for student (multiple students one problem) or  =item * $identifier: counter for student (multiple students one problem) or 
     problem (one student; whole sequence).      problem (one student; whole sequence).
   
 =back  =back
Line 4332  sub get_previous_attempt { Line 4120  sub get_previous_attempt {
             my (@hidden,@unsolved);              my (@hidden,@unsolved);
             if (%typeparts) {              if (%typeparts) {
                 foreach my $id (keys(%typeparts)) {                  foreach my $id (keys(%typeparts)) {
                     if (($returnhash{$version.':'.$id.'.type'} eq 'anonsurvey') ||                      if (($returnhash{$version.':'.$id.'.type'} eq 'anonsurvey') || 
                         ($returnhash{$version.':'.$id.'.type'} eq 'anonsurveycred')) {                          ($returnhash{$version.':'.$id.'.type'} eq 'anonsurveycred')) {
                         push(@hidden,$id);                          push(@hidden,$id);
                     } elsif ($identifier ne '') {                      } elsif ($identifier ne '') {
Line 4393  sub get_previous_attempt { Line 4181  sub get_previous_attempt {
                         if ($key =~ /\./) {                          if ($key =~ /\./) {
                             my $value = $returnhash{$version.':'.$key};                              my $value = $returnhash{$version.':'.$key};
                             if ($key =~ /\.rndseed$/) {                              if ($key =~ /\.rndseed$/) {
                                 my ($id) = ($key =~ /^(.+)\.rndseed$/);                                  my ($id) = ($key =~ /^(.+)\.[^.]+$/);
                                 if (exists($returnhash{$version.':'.$id.'.rawrndseed'})) {                                  if (exists($returnhash{$version.':'.$id.'.rawrndseed'})) {
                                     $value = $returnhash{$version.':'.$id.'.rawrndseed'};                                      $value = $returnhash{$version.':'.$id.'.rawrndseed'};
                                 }                                  }
Line 4410  sub get_previous_attempt { Line 4198  sub get_previous_attempt {
                     next if ($key =~ /\.foilorder$/);                      next if ($key =~ /\.foilorder$/);
                     my $value = $returnhash{$version.':'.$key};                      my $value = $returnhash{$version.':'.$key};
                     if ($key =~ /\.rndseed$/) {                      if ($key =~ /\.rndseed$/) {
                         my ($id) = ($key =~ /^(.+)\.rndseed$/);                          my ($id) = ($key =~ /^(.+)\.[^.]+$/);
                         if (exists($returnhash{$version.':'.$id.'.rawrndseed'})) {                          if (exists($returnhash{$version.':'.$id.'.rawrndseed'})) {
                             $value = $returnhash{$version.':'.$id.'.rawrndseed'};                              $value = $returnhash{$version.':'.$id.'.rawrndseed'};
                         }                          }
Line 4441  sub get_previous_attempt { Line 4229  sub get_previous_attempt {
                       if ($key =~/$regexp$/ && (defined &$gradesub)) {                        if ($key =~/$regexp$/ && (defined &$gradesub)) {
                           $value = &$gradesub($value);                            $value = &$gradesub($value);
                       }                        }
                       $prevattempts.='<td>'.$value.'&nbsp;</td>';                        $prevattempts.='<td>'. $value.'&nbsp;</td>';
                   } else {                    } else {
                       $prevattempts.='<td>&nbsp;</td>';                        $prevattempts.='<td>&nbsp;</td>';
                   }                    }
Line 4457  sub get_previous_attempt { Line 4245  sub get_previous_attempt {
       if ($key =~/$regexp$/ && (defined &$gradesub)) {        if ($key =~/$regexp$/ && (defined &$gradesub)) {
                   $value = &$gradesub($value);                    $value = &$gradesub($value);
               }                }
       $prevattempts.='<td>'.$value.'&nbsp;</td>';       $prevattempts.='<td>'.$value.'&nbsp;</td>';
           }            }
       }        }
       $prevattempts.= &end_data_table_row().&end_data_table();        $prevattempts.= &end_data_table_row().&end_data_table();
Line 4478  sub get_previous_attempt { Line 4266  sub get_previous_attempt {
 sub format_previous_attempt_value {  sub format_previous_attempt_value {
     my ($key,$value) = @_;      my ($key,$value) = @_;
     if (($key =~ /timestamp/) || ($key=~/duedate/)) {      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 = &HTML::Entities::encode('('.join(', ', @{ $value }).')','"<>&');
     } elsif ($key =~ /answerstring$/) {      } elsif ($key =~ /answerstring$/) {
         my %answers = &Apache::lonnet::str2hash($value);          my %answers = &Apache::lonnet::str2hash($value);
           my @answer = %answers;
           %answers = map {&HTML::Entities::encode($_, '"<>&')} @answer;
         my @anskeys = sort(keys(%answers));          my @anskeys = sort(keys(%answers));
         if (@anskeys == 1) {          if (@anskeys == 1) {
             my $answer = $answers{$anskeys[0]};              my $answer = $answers{$anskeys[0]};
Line 4505  sub format_previous_attempt_value { Line 4295  sub format_previous_attempt_value {
             }               } 
         }          }
     } else {      } else {
  $value = &unescape($value);          $value = &HTML::Entities::encode(&unescape($value), '"<>&');
     }      }
     return $value;      return $value;
 }  }
Line 4611  sub get_student_view_with_retries { Line 4401  sub get_student_view_with_retries {
     }      }
 }  }
   
 sub css_links {  
     my ($currsymb,$level) = @_;  
     my ($links,@symbs,%cssrefs,%httpref);  
     if ($level eq 'map') {  
         my $navmap = Apache::lonnavmaps::navmap->new();  
         if (ref($navmap)) {  
             my ($map,undef,$url)=&Apache::lonnet::decode_symb($currsymb);  
             my @resources = $navmap->retrieveResources($map,sub { $_[0]->is_problem() },0,0);  
             foreach my $res (@resources) {  
                 if (ref($res) && $res->symb()) {  
                     push(@symbs,$res->symb());  
                 }  
             }  
         }  
     } else {  
         @symbs = ($currsymb);  
     }  
     foreach my $symb (@symbs) {  
         my $css_href = &Apache::lonnet::EXT('resource.0.cssfile',$symb);  
         if ($css_href =~ /\S/) {  
             unless ($css_href =~ m{https?://}) {  
                 my $url = (&Apache::lonnet::decode_symb($symb))[-1];  
                 my $proburl =  &Apache::lonnet::clutter($url);  
                 my ($probdir) = ($proburl =~ m{(.+)/[^/]+$});  
                 unless ($css_href =~ m{^/}) {  
                     $css_href = &Apache::lonnet::hreflocation($probdir,$css_href);  
                 }  
                 if ($css_href =~ m{^/(res|uploaded)/}) {  
                     unless (($httpref{'httpref.'.$css_href}) ||  
                             (&Apache::lonnet::is_on_map($css_href))) {  
                         my $thisurl = $proburl;  
                         if ($env{'httpref.'.$proburl}) {  
                             $thisurl = $env{'httpref.'.$proburl};  
                         }  
                         $httpref{'httpref.'.$css_href} = $thisurl;  
                     }  
                 }  
             }  
             $cssrefs{$css_href} = 1;  
         }  
     }  
     if (keys(%httpref)) {  
         &Apache::lonnet::appenv(\%httpref);  
     }  
     if (keys(%cssrefs)) {  
         foreach my $css_href (keys(%cssrefs)) {  
             next unless ($css_href =~ m{^(/res/|/uploaded/|https?://)});  
             $links .= '<link rel="stylesheet" type="text/css" href="'.$css_href.'" />'."\n";  
         }  
     }  
     return $links;  
 }  
   
 =pod  =pod
   
 =item * &get_student_answers()   =item * &get_student_answers() 
Line 4919  sub findallcourses { Line 4656  sub findallcourses {
 ###############################################  ###############################################
   
 sub blockcheck {  sub blockcheck {
     my ($setters,$activity,$clientip,$uname,$udom,$url,$is_course,$symb,$caller) = @_;      my ($setters,$activity,$uname,$udom,$url,$is_course) = @_;
   
     unless (($activity eq 'docs') || ($activity eq 'reinit') || ($activity eq 'alert')) {  
         my ($has_evb,$check_ipaccess);  
         my $dom = $env{'user.domain'};  
         if ($env{'request.course.id'}) {  
             my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};  
             my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};  
             my $checkrole = "cm./$cdom/$cnum";  
             my $sec = $env{'request.course.sec'};  
             if ($sec ne '') {  
                 $checkrole .= "/$sec";  
             }  
             if ((&Apache::lonnet::allowed('evb',undef,undef,$checkrole)) &&  
                 ($env{'request.role'} !~ /^st/)) {  
                 $has_evb = 1;  
             }  
             unless ($has_evb) {  
                 if (($activity eq 'printout') || ($activity eq 'grades') || ($activity eq 'search') ||  
                     ($activity eq 'boards') || ($activity eq 'groups') || ($activity eq 'chat')) {  
                     if ($udom eq $cdom) {  
                         $check_ipaccess = 1;  
                     }  
                 }  
             }  
         } elsif (($activity eq 'com') || ($activity eq 'port') || ($activity eq 'blogs') ||  
                 ($activity eq 'about') || ($activity eq 'wishlist') || ($activity eq 'passwd')) {  
             my $checkrole;  
             if ($env{'request.role.domain'} eq '') {  
                 $checkrole = "cm./$env{'user.domain'}/";  
             } else {  
                 $checkrole = "cm./$env{'request.role.domain'}/";  
             }  
             if (($checkrole) && (&Apache::lonnet::allowed('evb',undef,undef,$checkrole))) {  
                 $has_evb = 1;  
             }  
         }  
         unless ($has_evb || $check_ipaccess) {  
             my @machinedoms = &Apache::lonnet::current_machine_domains();  
             if (($dom eq 'public') && ($activity eq 'port')) {  
                 $dom = $udom;  
             }  
             if (($dom ne '') && (grep(/^\Q$dom\E$/,@machinedoms))) {  
                 $check_ipaccess = 1;  
             } else {  
                 my $lonhost = $Apache::lonnet::perlvar{'lonHostID'};  
                 my $internet_names = &Apache::lonnet::get_internet_names($lonhost);  
                 my $prim = &Apache::lonnet::domain($dom,'primary');  
                 my $intdom = &Apache::lonnet::internet_dom($prim);  
                 if (($intdom ne '') && (ref($internet_names) eq 'ARRAY')) {  
                     if (grep(/^\Q$intdom\E$/,@{$internet_names})) {  
                         $check_ipaccess = 1;  
                     }  
                 }  
             }  
         }  
         if ($check_ipaccess) {  
             my ($ipaccessref,$cached)=&Apache::lonnet::is_cached_new('ipaccess',$dom);  
             unless (defined($cached)) {  
                 my %domconfig =  
                     &Apache::lonnet::get_dom('configuration',['ipaccess'],$dom);  
                 $ipaccessref = &Apache::lonnet::do_cache_new('ipaccess',$dom,$domconfig{'ipaccess'},1800);  
             }  
             if ((ref($ipaccessref) eq 'HASH') && ($clientip)) {  
                 foreach my $id (keys(%{$ipaccessref})) {  
                     if (ref($ipaccessref->{$id}) eq 'HASH') {  
                         my $range = $ipaccessref->{$id}->{'ip'};  
                         if ($range) {  
                             if (&Apache::lonnet::ip_match($clientip,$range)) {  
                                 if (ref($ipaccessref->{$id}->{'commblocks'}) eq 'HASH') {  
                                     if ($ipaccessref->{$id}->{'commblocks'}->{$activity} eq 'on') {  
                                         return ('','','',$id,$dom);  
                                         last;  
                                     }  
                                 }  
                             }  
                         }  
                     }  
                 }  
             }  
         }  
         if (($activity eq 'wishlist') || ($activity eq 'annotate')) {  
             return ();  
         }  
     }  
     if (defined($udom) && defined($uname)) {      if (defined($udom) && defined($uname)) {
         # 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 (($is_course) || (&Apache::lonnet::is_course($udom,$uname))) {          if (($is_course) || (&Apache::lonnet::is_course($udom,$uname))) {
             my ($startblock,$endblock,$triggerblock) =              my ($startblock,$endblock,$triggerblock) =
                 &get_blocks($setters,$activity,$udom,$uname,$url,$symb,$caller);                  &get_blocks($setters,$activity,$udom,$uname,$url);
             return ($startblock,$endblock,$triggerblock);              return ($startblock,$endblock,$triggerblock);
         }          }
     } else {      } else {
Line 5019  sub blockcheck { Line 4673  sub blockcheck {
     my $startblock = 0;      my $startblock = 0;
     my $endblock = 0;      my $endblock = 0;
     my $triggerblock = '';      my $triggerblock = '';
     my %live_courses;      my %live_courses = &findallcourses(undef,$uname,$udom);
     unless (($activity eq 'wishlist') || ($activity eq 'annotate')) {  
         %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.,
     # boards, chat or groups, check for blocking in current course only.      # boards, chat or groups, check for blocking in current course only.
   
     if (($activity eq 'boards' || $activity eq 'chat' ||      if (($activity eq 'boards' || $activity eq 'chat' ||
          $activity eq 'groups' || $activity eq 'printout' ||           $activity eq 'groups' || $activity eq 'printout') &&
          $activity eq 'search' || $activity eq 'reinit' ||          ($env{'request.course.id'})) {
          $activity eq 'alert') && ($env{'request.course.id'})) {  
         foreach my $key (keys(%live_courses)) {          foreach my $key (keys(%live_courses)) {
             if ($key ne $env{'request.course.id'}) {              if ($key ne $env{'request.course.id'}) {
                 delete($live_courses{$key});                  delete($live_courses{$key});
Line 5113  sub blockcheck { Line 4763  sub blockcheck {
                                                                 $tdom,$spec,$trest,$area);                                                                  $tdom,$spec,$trest,$area);
                         }                          }
                     }                      }
                     my ($author,$adv,$rar) = &Apache::lonnet::set_userprivs(\%userroles,\%allroles);                      my ($author,$adv) = &Apache::lonnet::set_userprivs(\%userroles,\%allroles);
                     if ($userroles{'user.priv.'.$checkrole} =~ /evb\&([^\:]*)/) {                      if ($userroles{'user.priv.'.$checkrole} =~ /evb\&([^\:]*)/) {
                         if ($1) {                          if ($1) {
                             $no_userblock = 1;                              $no_userblock = 1;
Line 5135  sub blockcheck { Line 4785  sub blockcheck {
                  ($env{'request.role'} !~ m{^st\./\Q$cdom\E/\Q$cnum\E}));                   ($env{'request.role'} !~ m{^st\./\Q$cdom\E/\Q$cnum\E}));
         next if ($no_userblock);          next if ($no_userblock);
   
         # Retrieve blocking times and identity of blocker 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,$trigger) =           my ($start,$end,$trigger) = 
             &get_blocks($setters,$activity,$cdom,$cnum,$url,$symb,$caller);              &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;
Line 5159  sub blockcheck { Line 4809  sub blockcheck {
 }  }
   
 sub get_blocks {  sub get_blocks {
     my ($setters,$activity,$cdom,$cnum,$url,$symb,$caller) = @_;      my ($setters,$activity,$cdom,$cnum,$url) = @_;
     my $startblock = 0;      my $startblock = 0;
     my $endblock = 0;      my $endblock = 0;
     my $triggerblock = '';      my $triggerblock = '';
Line 5172  sub get_blocks { Line 4822  sub get_blocks {
     my $now = time;      my $now = time;
     my %commblocks = &Apache::lonnet::get_comm_blocks($cdom,$cnum);      my %commblocks = &Apache::lonnet::get_comm_blocks($cdom,$cnum);
     if ($activity eq 'docs') {      if ($activity eq 'docs') {
         my ($blocked,$nosymbcache,$noenccheck);          @blockers = &Apache::lonnet::has_comm_blocking('bre',undef,$url,\%commblocks);
         if (($caller eq 'blockedaccess') || ($caller eq 'blockingstatus')) {  
             $blocked = 1;  
             $nosymbcache = 1;  
             $noenccheck = 1;  
         }  
         @blockers = &Apache::lonnet::has_comm_blocking('bre',$symb,$url,$nosymbcache,$noenccheck,$blocked,\%commblocks);  
         foreach my $block (@blockers) {          foreach my $block (@blockers) {
             if ($block =~ /^firstaccess____(.+)$/) {              if ($block =~ /^firstaccess____(.+)$/) {
                 my $item = $1;                  my $item = $1;
Line 5230  sub get_blocks { Line 4874  sub get_blocks {
                 my $end = $start + $env{'course.'.$cdom.'_'.$cnum.'.timerinterval.'.$timersymb};                   my $end = $start + $env{'course.'.$cdom.'_'.$cnum.'.timerinterval.'.$timersymb}; 
                 if ($start && $end) {                  if ($start && $end) {
                     if (($start <= time) && ($end >= time)) {                      if (($start <= time) && ($end >= time)) {
                         if (ref($commblocks{$block}) eq 'HASH') {                          unless (grep(/^\Q$block\E$/,@blockers)) {
                             if (ref($commblocks{$block}{'blocks'}) eq 'HASH') {                              push(@blockers,$block);
                                 if ($commblocks{$block}{'blocks'}{$activity} eq 'on') {                              $triggered{$block} = {
                                     unless(grep(/^\Q$block\E$/,@blockers)) {                                                     start => $start,
                                         push(@blockers,$block);                                                     end   => $end,
                                         $triggered{$block} = {                                                     type  => $type,
                                                                start => $start,                                                   };
                                                                end   => $end,  
                                                                type  => $type,  
                                                              };  
                                     }  
                                 }  
                             }  
                         }                          }
                     }                      }
                 }                  }
Line 5306  sub parse_block_record { Line 4944  sub parse_block_record {
 }  }
   
 sub blocking_status {  sub blocking_status {
     my ($activity,$clientip,$uname,$udom,$url,$is_course,$symb,$caller) = @_;      my ($activity,$uname,$udom,$url,$is_course) = @_;
     my %setters;      my %setters;
   
 # check for active blocking  # check for active blocking
     if ($clientip eq '') {      my ($startblock,$endblock,$triggerblock) = 
         $clientip = &Apache::lonnet::get_requestor_ip();          &blockcheck(\%setters,$activity,$uname,$udom,$url,$is_course);
     }  
     my ($startblock,$endblock,$triggerblock,$by_ip,$blockdom) =   
         &blockcheck(\%setters,$activity,$clientip,$uname,$udom,$url,$is_course,$symb,$caller);  
     my $blocked = 0;      my $blocked = 0;
     if (($startblock && $endblock) || ($by_ip)) {      if ($startblock && $endblock) {
         $blocked = 1;          $blocked = 1;
     }      }
   
Line 5325  sub blocking_status { Line 4960  sub blocking_status {
   
 # build a link to a popup window containing the details  # build a link to a popup window containing the details
     my $querystring  = "?activity=$activity";      my $querystring  = "?activity=$activity";
 # $uname and $udom decide whose portfolio (or information page) the user is trying to look at  # $uname and $udom decide whose portfolio the user is trying to look at
     if (($activity eq 'port') || ($activity eq 'about') || ($activity eq 'passwd')) {      if (($activity eq 'port') || ($activity eq 'passwd')) {
         $querystring .= "&amp;udom=$udom"      if ($udom =~ /^$match_domain$/);          $querystring .= "&amp;udom=$udom"      if ($udom =~ /^$match_domain$/); 
         $querystring .= "&amp;uname=$uname"    if ($uname =~ /^$match_username$/);          $querystring .= "&amp;uname=$uname"    if ($uname =~ /^$match_username$/);
     } elsif ($activity eq 'docs') {      } elsif ($activity eq 'docs') {
         my $showurl = &Apache::lonenc::check_encrypt($url);          $querystring .= '&amp;url='.&HTML::Entities::encode($url,'&"');
         $querystring .= '&amp;url='.&HTML::Entities::encode($showurl,'\'&"<>');  
         if ($symb) {  
             my $showsymb = &Apache::lonenc::check_encrypt($symb);  
             $querystring .= '&amp;symb='.&HTML::Entities::encode($showsymb,'\'&"<>');  
         }  
     }      }
   
     my $output .= <<'END_MYBLOCK';      my $output .= <<'END_MYBLOCK';
Line 5360  END_MYBLOCK Line 4990  END_MYBLOCK
         $text = &mt('Printing Blocked');          $text = &mt('Printing Blocked');
     } elsif ($activity eq 'passwd') {      } elsif ($activity eq 'passwd') {
         $text = &mt('Password Changing Blocked');          $text = &mt('Password Changing Blocked');
     } elsif ($activity eq 'grades') {  
         $text = &mt('Gradebook Blocked');  
     } elsif ($activity eq 'search') {  
         $text = &mt('Search Blocked');  
     } elsif ($activity eq 'alert') {  
         $text = &mt('Checking Critical Messages Blocked');  
     } elsif ($activity eq 'reinit') {  
         $text = &mt('Checking Course Update Blocked');  
     } elsif ($activity eq 'about') {  
         $text = &mt('Access to User Information Pages Blocked');  
     } elsif ($activity eq 'wishlist') {  
         $text = &mt('Access to Stored Links Blocked');  
     } elsif ($activity eq 'annotate') {  
         $text = &mt('Access to Annotations Blocked');  
     }      }
     $output .= <<"END_BLOCK";      $output .= <<"END_BLOCK";
 <div class='$class'>  <div class='$class'>
Line 5397  sub check_ip_acc { Line 5013  sub check_ip_acc {
     if (!defined($acc) || $acc =~ /^\s*$/ || $acc =~/^\s*no\s*$/i) {      if (!defined($acc) || $acc =~ /^\s*$/ || $acc =~/^\s*no\s*$/i) {
         return 1;          return 1;
     }      }
     my $allowed=0;      my $allowed;
     my $ip;      my $ip=$env{'request.host'} || $ENV{'REMOTE_ADDR'} || $clientip;
     if (($ENV{'REMOTE_ADDR'} eq '127.0.0.1') ||  
         ($ENV{'REMOTE_ADDR'} eq &Apache::lonnet::get_host_ip($Apache::lonnet::perlvar{'lonHostID'}))) {  
         $ip = $env{'request.host'} || $ENV{'REMOTE_ADDR'} || $clientip;  
     } else {  
         my $remote_ip = &Apache::lonnet::get_requestor_ip();  
         $ip = $remote_ip || $env{'request.host'} || $clientip;  
     }  
   
     my $name;      my $name;
     my %access = (      my %access = (
Line 5417  sub check_ip_acc { Line 5026  sub check_ip_acc {
     foreach my $item (split(',',$acc)) {      foreach my $item (split(',',$acc)) {
         $item =~ s/^\s*//;          $item =~ s/^\s*//;
         $item =~ s/\s*$//;          $item =~ s/\s*$//;
           my $pattern;
         if ($item =~ /^\!(.+)$/) {          if ($item =~ /^\!(.+)$/) {
             push(@denies,$1);              push(@denies,$1);
         } else {          } else {
             push(@allows,$item);              push(@allows,$item);
         }          }
     }     }
     my $numdenies = scalar(@denies);     my $numdenies = scalar(@denies);
     my $numallows = scalar(@allows);     my $numallows = scalar(@allows);
     my $count = 0;     my $count = 0;
     foreach my $pattern (@denies,@allows) {     foreach my $pattern (@denies,@allows) {
         $count ++;          $count ++; 
         my $acctype = 'allowfrom';          my $acctype = 'allowfrom';
         if ($count <= $numdenies) {          if ($count <= $numdenies) {
             $acctype = 'denyfrom';              $acctype = 'denyfrom';
Line 5538  sub get_domainconf { Line 5148  sub get_domainconf {
                                                 my $server = $domconfig{'login'}{'loginvia'}{$hostname}{'server'};                                                  my $server = $domconfig{'login'}{'loginvia'}{$hostname}{'server'};
                                                 $designhash{$udom.'.login.loginvia'} = $server;                                                  $designhash{$udom.'.login.loginvia'} = $server;
                                                 if ($domconfig{'login'}{'loginvia'}{$hostname}{'serverpath'} eq 'custom') {                                                  if ($domconfig{'login'}{'loginvia'}{$hostname}{'serverpath'} eq 'custom') {
   
                                                     $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'};
Line 5554  sub get_domainconf { Line 5165  sub get_domainconf {
                                     }                                      }
                                 }                                  }
                             }                              }
                         } elsif ($key eq 'saml') {  
                             if (ref($domconfig{'login'}{$key}) eq 'HASH') {  
                                 foreach my $host (keys(%{$domconfig{'login'}{$key}})) {  
                                     if (ref($domconfig{'login'}{$key}{$host}) eq 'HASH') {  
                                         $designhash{$udom.'.login.'.$key.'_'.$host} = 1;  
                                         foreach my $item ('text','img','alt','url','title','window','notsso') {  
                                             $designhash{$udom.'.login.'.$key.'_'.$item.'_'.$host} = $domconfig{'login'}{$key}{$host}{$item};  
                                         }  
                                     }  
                                 }  
                             }  
                         } else {                          } else {
                             foreach my $img (keys(%{$domconfig{'login'}{$key}})) {                              foreach my $img (keys(%{$domconfig{'login'}{$key}})) {
                                 $designhash{$udom.'.login.'.$key.'_'.$img} =                                   $designhash{$udom.'.login.'.$key.'_'.$img} = 
Line 5629  sub get_legacy_domconf { Line 5229  sub get_legacy_domconf {
     my $designdir=$Apache::lonnet::perlvar{'lonTabDir'}.'/lonDomColors';      my $designdir=$Apache::lonnet::perlvar{'lonTabDir'}.'/lonDomColors';
     my $designfile =  $designdir.'/'.$udom.'.tab';      my $designfile =  $designdir.'/'.$udom.'.tab';
     if (-e $designfile) {      if (-e $designfile) {
         if ( open (my $fh,'<',$designfile) ) {          if ( open (my $fh,"<$designfile") ) {
             while (my $line = <$fh>) {              while (my $line = <$fh>) {
                 next if ($line =~ /^\#/);                  next if ($line =~ /^\#/);
                 chomp($line);                  chomp($line);
Line 5669  sub domainlogo { Line 5269  sub domainlogo {
  &Apache::lonnet::repcopy($local_name);   &Apache::lonnet::repcopy($local_name);
     }      }
    $imgsrc = &lonhttpdurl($imgsrc);     $imgsrc = &lonhttpdurl($imgsrc);
         }          } 
         my $alttext = $domain;          return '<img src="'.$imgsrc.'" alt="'.$domain.'" />';
         if ($designhash{$domain.'.login.alttext_domlogo'} ne '') {  
             $alttext = $designhash{$domain.'.login.alttext_domlogo'};  
         }  
         return '<img src="'.$imgsrc.'" alt="'.$alttext.'" id="lclogindomlogo" />';  
     } elsif (defined(&Apache::lonnet::domain($domain,'description'))) {      } elsif (defined(&Apache::lonnet::domain($domain,'description'))) {
         return &Apache::lonnet::domain($domain,'description');          return &Apache::lonnet::domain($domain,'description');
     } else {      } else {
Line 5792  sub head_subbox { Line 5388  sub head_subbox {
 Input: (optional) filename from which breadcrumb trail is built.  Input: (optional) filename from which breadcrumb trail is built.
        In most cases no input as needed, as $env{'request.filename'}         In most cases no input as needed, as $env{'request.filename'}
        is appropriate for use in building the breadcrumb trail.         is appropriate for use in building the breadcrumb trail.
        frameset flag  
        If page header is being requested for use in a frameset, then  
        the second (option) argument -- frameset will be true, and  
        the target attribute set for links should be target="_parent".  
   
 Returns: HTML div with CSTR path and recent box  Returns: HTML div with CSTR path and recent box
          To be included on Authoring Space pages           To be included on Authoring Space pages
Line 5803  Returns: HTML div with CSTR path and rec Line 5395  Returns: HTML div with CSTR path and rec
 =cut  =cut
   
 sub CSTR_pageheader {  sub CSTR_pageheader {
     my ($trailfile,$frameset) = @_;      my ($trailfile) = @_;
     if ($trailfile eq '') {      if ($trailfile eq '') {
         $trailfile = $env{'request.filename'};          $trailfile = $env{'request.filename'};
     }      }
Line 5826  sub CSTR_pageheader { Line 5418  sub CSTR_pageheader {
         $lastitem = $thisdisfn;          $lastitem = $thisdisfn;
     }      }
   
     my ($target,$crumbtarget) = (' target="_top"','_top');  
     if ($frameset) {  
         $target = ' target="_parent"';  
         $crumbtarget = '_parent';  
     } elsif (($env{'request.deeplink.login'}) && ($env{'request.deeplink.target'})) {  
         $target = ' target="'.$env{'request.deeplink.target'}.'"';  
         $crumbtarget = $env{'request.deeplink.target'};  
     }  
   
     my $output =      my $output =
          '<div>'           '<div>'
         .&Apache::loncommon::help_open_menu('','',3,'Authoring') #FIXME: Broken? Where is it?          .&Apache::loncommon::help_open_menu('','',3,'Authoring') #FIXME: Broken? Where is it?
         .'<b>'.&mt('Authoring Space:').'</b> '          .'<b>'.&mt('Authoring Space:').'</b> '
         .'<form name="dirs" method="post" action="'.$formaction.'"'.$target.'>'          .'<form name="dirs" method="post" action="'.$formaction
         .&Apache::lonhtmlcommon::crumbs($uname.'/'.$parentpath,$crumbtarget,'/priv/'.$udom,undef,undef);          .'" target="_top">' #FIXME lonpubdir: target="_parent"
           .&Apache::lonhtmlcommon::crumbs($uname.'/'.$parentpath,'_top','/priv/'.$udom,undef,undef);
   
     if ($lastitem) {      if ($lastitem) {
         $output .=          $output .=
Line 5850  sub CSTR_pageheader { Line 5434  sub CSTR_pageheader {
     }      }
     $output .=      $output .=
          '<br />'           '<br />'
         #FIXME lonpubdir: &Apache::lonhtmlcommon::crumbs($uname.$thisdisfn.'/',$crumbtarget,'/priv','','+1',1)."</b></tt><br />"          #FIXME lonpubdir: &Apache::lonhtmlcommon::crumbs($uname.$thisdisfn.'/','_top','/priv','','+1',1)."</b></tt><br />"
         .&Apache::lonhtmlcommon::select_recent('construct','recent','this.form.action=this.form.recent.value;this.form.submit()')          .&Apache::lonhtmlcommon::select_recent('construct','recent','this.form.action=this.form.recent.value;this.form.submit()')
         .'</form>'          .'</form>'
         .&Apache::lonmenu::constspaceform($frameset)          .&Apache::lonmenu::constspaceform()
         .'</div>';          .'</div>';
   
     return $output;      return $output;
Line 5896  Inputs: Line 5480  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
             use_absolute     -> for external resource or syllabus, this will  
                                 contain https://<hostname> if server uses  
                                 https (as per hosts.tab), but request is for http  
             hostname         -> hostname, from $r->hostname().  
   
 =item * $advtoolsref, optional argument, ref to an array containing  =item * $advtoolsref, optional argument, ref to an array containing
             inlineremote items to be added in "Functions" menu below              inlineremote items to be added in "Functions" menu below
             breadcrumbs.              breadcrumbs.
   
 =item * $ltiscope, optional argument, will be one of: resource, map or  
             course, if LON-CAPA is in LTI Provider context. Value is  
             the scope of use, i.e., launch was for access to a single, a map  
             or the entire course.  
   
 =item * $ltiuri, optional argument, if LON-CAPA is in LTI Provider  
             context, this will contain the URL for the landing item in  
             the course, after launch from an LTI Consumer  
   
 =item * $ltimenu, optional argument, if LON-CAPA is in LTI Provider  
             context, this will contain a reference to hash of items  
             to be included in the page header and/or inline menu.  
   
 =item * $menucoll, optional argument, if specific menu collection is in  
             effect, either set as the default for the course, or set for  
             the deeplink paramater for $env{'request.deeplink.login'}  
             then $menucoll will be the number of that collection.  
   
 =item * $menuref, optional argument, reference to a hash, containing the  
             menu options included for the menu in effect, based on the  
             configuration for the numbered menu collection in use.  
   
 =item * $showncrumbsref, reference to a scalar. Calls to lonmenu::innerregister  
             within &bodytag() can result in calls to lonhtmlcommon::breadcrumbs(),  
             if so, $showncrumbsref is set there to 1, and will propagate back  
             via &bodytag() to &start_page(), to prevent lonhtmlcommon::breadcrumbs()  
             being called a second time.  
   
 =back  =back
   
 Returns: A uniform header for LON-CAPA web pages.    Returns: A uniform header for LON-CAPA web pages.  
Line 5949  other decorations will be returned. Line 5498  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,$advtoolsref,          $no_nav_bar,$bgcolor,$args,$advtoolsref)=@_;
         $ltiscope,$ltiuri,$ltimenu,$menucoll,$menuref,$showncrumbsref)=@_;  
   
     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 5959  sub bodytag { Line 5507  sub bodytag {
     }      }
     if (!$args->{'no_auto_mt_title'}) { $title = &mt($title); }      if (!$args->{'no_auto_mt_title'}) { $title = &mt($title); }
     my $httphost = $args->{'use_absolute'};      my $httphost = $args->{'use_absolute'};
     my $hostname = $args->{'hostname'};  
   
     $function = &get_users_function() if (!$function);      $function = &get_users_function() if (!$function);
     my $img =    &designparm($function.'.img',$domain);      my $img =    &designparm($function.'.img',$domain);
Line 5979  sub bodytag { Line 5526  sub bodytag {
     if ($realm) {      if ($realm) {
         $realm = '/'.$realm;          $realm = '/'.$realm;
     }      }
     if ($role eq 'ca') {      if ($role  eq 'ca') {
         my ($rdom,$rname) = ($realm =~ m{^/($match_domain)/($match_username)$});          my ($rdom,$rname) = ($realm =~ m{^/($match_domain)/($match_username)$});
         $realm = &plainname($rname,$rdom);          $realm = &plainname($rname,$rdom);
     }       } 
 # realm  # realm
     my ($cid,$sec);  
     if ($env{'request.course.id'}) {      if ($env{'request.course.id'}) {
         $cid = $env{'request.course.id'};  
         if ($env{'request.course.sec'}) {  
             $sec = $env{'request.course.sec'};  
         }  
     } elsif ($realm =~ m{^/($match_domain)/($match_courseid)(?:|/(\w+))$}) {  
         if (&Apache::lonnet::is_course($1,$2)) {  
             $cid = $1.'_'.$2;  
             $sec = $3;  
         }  
     }  
     if ($cid) {  
         if ($env{'request.role'} !~ /^cr/) {          if ($env{'request.role'} !~ /^cr/) {
             $role = &Apache::lonnet::plaintext($role,&course_type());              $role = &Apache::lonnet::plaintext($role,&course_type());
         } elsif ($role =~ m{^cr/($match_domain)/\1-domainconfig/(\w+)$}) {  
             if ($env{'request.role.desc'}) {  
                 $role = $env{'request.role.desc'};  
             } else {  
                 $role = &mt('Helpdesk[_1]','&nbsp;'.$2);  
             }  
         } else {  
             $role = (split(/\//,$role,4))[-1];  
         }          }
         if ($sec) {          if ($env{'request.course.sec'}) {
             $role .= ('&nbsp;'x2).'-&nbsp;'.&mt('section:').'&nbsp;'.$sec;              $role .= ('&nbsp;'x2).'-&nbsp;'.&mt('section:').'&nbsp;'.$env{'request.course.sec'};
         }             }   
  $realm = $env{'course.'.$cid.'.description'};   $realm = $env{'course.'.$env{'request.course.id'}.'.description'};
     } else {      } else {
         $role = &Apache::lonnet::plaintext($role);          $role = &Apache::lonnet::plaintext($role);
     }      }
Line 6033  sub bodytag { Line 5560  sub bodytag {
     if ($public) {      if ($public) {
  undef($role);   undef($role);
     }      }
       
     my $showcrstitle = 1;  
     if (($cid) && ($env{'request.lti.login'})) {  
         if (ref($ltimenu) eq 'HASH') {  
             unless ($ltimenu->{'role'}) {  
                 undef($role);  
             }  
             unless ($ltimenu->{'coursetitle'}) {  
                 $realm='&nbsp;';  
                 $showcrstitle = 0;  
             }  
         }  
     } elsif (($cid) && ($menucoll)) {  
         if (ref($menuref) eq 'HASH') {  
             unless ($menuref->{'role'}) {  
                 undef($role);  
             }  
             unless ($menuref->{'crs'}) {  
                 $realm='&nbsp;';  
                 $showcrstitle = 0;  
             }  
         }  
     }  
   
     my $titleinfo = '<h1>'.$title.'</h1>';      my $titleinfo = '<h1>'.$title.'</h1>';
     #      #
     # Extra info if you are the DC      # Extra info if you are the DC
     my $dc_info = '';      my $dc_info = '';
     if (($env{'user.adv'}) && ($env{'request.course.id'}) && $showcrstitle &&      if ($env{'user.adv'} && exists($env{'user.role.dc./'.
         (exists($env{'user.role.dc./'.$env{'course.'.$cid.'.domain'}.'/'}))) {                          $env{'course.'.$env{'request.course.id'}.
                                    '.domain'}.'/'})) {
           my $cid = $env{'request.course.id'};
         $dc_info = $cid.' '.$env{'course.'.$cid.'.internal.coursecode'};          $dc_info = $cid.' '.$env{'course.'.$cid.'.internal.coursecode'};
         $dc_info =~ s/\s+$//;          $dc_info =~ s/\s+$//;
     }      }
   
     my $crstype;      $role = '<span class="LC_nobreak">('.$role.')</span>' if $role;
     if ($cid) {  
         $crstype = $env{'course.'.$cid.'.type'};  
     } elsif ($args->{'crstype'}) {  
         $crstype = $args->{'crstype'};  
     }  
   
     $role = '<span class="LC_nobreak">('.$role.')</span>' if ($role && !$env{'browser.mobile'});  
   
     if ($env{'request.state'} eq 'construct') { $forcereg=1; }  
   
   
           if ($env{'request.state'} eq 'construct') { $forcereg=1; }
     my $funclist;  
     if (($env{'environment.remote'} eq 'on') && ($env{'request.state'} ne 'construct')) {  
         $bodytag .= Apache::lonhtmlcommon::scripttag(Apache::lonmenu::utilityfunctions($httphost), 'start')."\n".  
                     Apache::lonmenu::serverform();  
         my $forbodytag;  
         &Apache::lonmenu::prepare_functions($env{'request.noversionuri'},  
                                             $forcereg,$args->{'group'},  
                                             $args->{'bread_crumbs'},  
                                             $advtoolsref,'','',\$forbodytag);  
         unless (ref($args->{'bread_crumbs'}) eq 'ARRAY') {  
             $funclist = $forbodytag;  
         }  
     } else {  
   
         #    if ($env{'request.state'} eq 'construct') {          #    if ($env{'request.state'} eq 'construct') {
         #        $titleinfo = &CSTR_pageheader(); #FIXME: Will be removed once all scripts have their own calls          #        $titleinfo = &CSTR_pageheader(); #FIXME: Will be removed once all scripts have their own calls
Line 6101  sub bodytag { Line 5584  sub bodytag {
         $bodytag .= Apache::lonhtmlcommon::scripttag(          $bodytag .= Apache::lonhtmlcommon::scripttag(
             Apache::lonmenu::utilityfunctions($httphost), 'start');              Apache::lonmenu::utilityfunctions($httphost), 'start');
   
         unless ($args->{'no_primary_menu'}) {          my ($left,$right) = Apache::lonmenu::primary_menu();
             my ($left,$right) = Apache::lonmenu::primary_menu($crstype,$ltimenu,$menucoll,$menuref,  
                                                               $args->{'links_disabled'},  
                                                               $args->{'links_target'});  
             if ($env{'request.noversionuri'} =~ m{^/res/adm/pages/}) {  
                 if ($dc_info) {  
                     $dc_info = qq|<span class="LC_cusr_subheading">$dc_info</span>|;  
                 }  
                 $bodytag .= qq|<div id="LC_nav_bar">$left $role<br />  
                                <em>$realm</em> $dc_info</div>|;  
                 return $bodytag;  
             }  
   
             unless ($env{'request.symb'} =~ m/\.page___\d+___/) {          if ($env{'request.noversionuri'} =~ m{^/res/adm/pages/}) {
                 $bodytag .= qq|<div id="LC_nav_bar">$left $role</div>|;               if ($dc_info) {
             }                   $dc_info = qq|<span class="LC_cusr_subheading">$dc_info</span>|;
                }
                $bodytag .= qq|<div id="LC_nav_bar">$left $role<br />
                   <em>$realm</em> $dc_info</div>|;
               return $bodytag;
           }
   
             $bodytag .= $right;          unless ($env{'request.symb'} =~ m/\.page___\d+___/) {
               $bodytag .= qq|<div id="LC_nav_bar">$left $role</div>|;
           }
   
             if ($dc_info) {          $bodytag .= $right;
                 $dc_info = &dc_courseid_toggle($dc_info);  
             }          if ($dc_info) {
             $bodytag .= qq|<div id="LC_realm">$realm $dc_info</div>|;              $dc_info = &dc_courseid_toggle($dc_info);
         }          }
           $bodytag .= qq|<div id="LC_realm">$realm $dc_info</div>|;
   
         #if directed to not display the secondary menu, don't.          #if directed to not display the secondary menu, don't.  
         if ($args->{'no_secondary_menu'}) {          if ($args->{'no_secondary_menu'}) {
             return $bodytag;              return $bodytag;
         }          }
         #don't show menus for public users          #don't show menus for public users
         if (!$public){          if (!$public){
             unless ($args->{'no_inline_menu'}) {              $bodytag .= Apache::lonmenu::secondary_menu($httphost);
                 $bodytag .= Apache::lonmenu::secondary_menu($httphost,$ltiscope,$ltimenu,  
                                                             $args->{'no_primary_menu'},  
                                                             $menucoll,$menuref,  
                                                             $args->{'links_disabled'},  
                                                             $args->{'links_target'});  
             }  
             $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'},'','',$hostname,                                  $args->{'bread_crumbs'});
                                 $ltiscope,$ltiuri,$showncrumbsref);  
             } elsif ($forcereg) {              } elsif ($forcereg) {
                 $bodytag .= &Apache::lonmenu::innerregister($forcereg,undef,                  $bodytag .= &Apache::lonmenu::innerregister($forcereg,undef,
                                 $args->{'group'},$args->{'hide_buttons'},                                                              $args->{'group'});
                                 $hostname,$ltiscope,$ltiuri,$showncrumbsref);  
             } else {              } else {
                 my $forbodytag;                  $bodytag .= 
                 &Apache::lonmenu::prepare_functions($env{'request.noversionuri'},                      &Apache::lonmenu::prepare_functions($env{'request.noversionuri'},
                                                     $forcereg,$args->{'group'},                                                          $forcereg,$args->{'group'},
                                                     $args->{'bread_crumbs'},                                                          $args->{'bread_crumbs'},
                                                     $advtoolsref,'',$hostname,                                                          $advtoolsref);
                                                     \$forbodytag);  
                 unless (ref($args->{'bread_crumbs'}) eq 'ARRAY') {  
                     $bodytag .= $forbodytag;  
                 }  
             }              }
         }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 6168  sub bodytag { Line 5636  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.'" />';  
   
     my $help=($no_inline_link?''  
               :&Apache::loncommon::top_nav_help('Help'));  
   
     # 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>|;  
     }  
   
     my $name = &plainname($env{'user.name'},$env{'user.domain'});  
     unless ($public) {  
         $name = &aboutmewrapper($name,$env{'user.name'},$env{'user.domain'},  
                                 undef,'LC_menubuttons_link');  
     }  
   
     unless ($env{'form.inhibitmenu'}) {  
         $bodytag .= qq|<div id="LC_nav_bar">$name $role</div>  
                        <ol class="LC_primary_menu LC_floatright LC_right">  
                        <li>$help</li>  
                        <li>$menu</li>  
                        </ol><div id="LC_realm"> $realm $dc_info</div>|;  
     }  
     if ($env{'request.state'} eq 'construct') {  
         if (!$public){  
             if ($env{'request.state'} eq 'construct') {  
                 $funclist = &Apache::lonhtmlcommon::scripttag(  
                                 &Apache::lonmenu::utilityfunctions($httphost), 'start').  
                             &Apache::lonhtmlcommon::scripttag('','end').  
                             &Apache::lonmenu::innerregister($forcereg,  
                                                             $args->{'bread_crumbs'});  
             }  
         }  
     }  
     return $bodytag."\n".$funclist;  
 }  }
   
 sub dc_courseid_toggle {  sub dc_courseid_toggle {
Line 6247  sub make_attr_string { Line 5667  sub make_attr_string {
  delete($attr_ref->{$key});   delete($attr_ref->{$key});
     }      }
  }   }
         if ($env{'environment.remote'} eq 'on') {   $attr_ref->{'onload'}  = $on_load;
             $attr_ref->{'onload'}  =   $attr_ref->{'onunload'}= $on_unload;
                 &Apache::lonmenu::loadevents().  $on_load;  
             $attr_ref->{'onunload'}=  
                 &Apache::lonmenu::unloadevents().$on_unload;  
         } else {    
     $attr_ref->{'onload'}  = $on_load;  
     $attr_ref->{'onunload'}= $on_unload;  
         }  
     }      }
   
     my $attr_string;      my $attr_string;
Line 6291  sub endbodytag { Line 5704  sub 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'})) {
             my ($endbodyjs,$idattr);  
             if ($env{'internal.head.to_opener'}) {  
                 my $linkid = 'LC_continue_link';  
                 $idattr = ' id="'.$linkid.'"';  
                 my $redirect_for_js = &js_escape($env{'internal.head.redirect'});  
                 $endbodyjs=<<ENDJS;  
 <script type="text/javascript">  
 // <![CDATA[  
 function ebFunction(evt) {  
     evt.preventDefault();  
     var dest = '$redirect_for_js';  
     if (window.opener != null && !window.opener.closed) {  
         window.opener.location.href=dest;  
         window.close();  
     } else {  
         window.location.href=dest;  
     }  
     return false;  
 }  
   
 \$(document).ready(function () {  
   if (document.getElementById('$linkid')) {  
     var clickelem = document.getElementById('$linkid');  
     clickelem.addEventListener('click',ebFunction,false);  
   }  
 });  
 // ]]>  
 </script>  
 ENDJS  
             }  
     $endbodytag=      $endbodytag=
         "$endbodyjs<br /><a href=\"$env{'internal.head.redirect'}\"$idattr>".          "<br /><a href=\"$env{'internal.head.redirect'}\">".
         &mt('Continue').'</a>'.          &mt('Continue').'</a>'.
         $endbodytag;          $endbodytag;
         }          }
Line 6493  div.LC_confirm_box .LC_success img { Line 5876  div.LC_confirm_box .LC_success img {
   vertical-align: middle;    vertical-align: middle;
 }  }
   
 .LC_maxwidth {  
   max-width: 100%;  
   height: auto;  
 }  
   
 .LC_textsize_mobile {  
   \@media only screen and (max-device-width: 480px) {  
       -webkit-text-size-adjust:100%; -moz-text-size-adjust:100%; -ms-text-size-adjust:100%;  
   }  
 }  
   
 .LC_icon {  .LC_icon {
   border: none;    border: none;
   vertical-align: middle;    vertical-align: middle;
Line 6625  table#LC_menubuttons img { Line 5997  table#LC_menubuttons img {
   vertical-align: middle;    vertical-align: middle;
 }  }
   
 .LC_breadcrumbs_hoverable {  
   background: $sidebg;  
 }  
   
 td.LC_table_cell_checkbox {  td.LC_table_cell_checkbox {
   text-align: center;    text-align: center;
 }  }
Line 6699  td.LC_menubuttons_text { Line 6067  td.LC_menubuttons_text {
   background: $tabbg;    background: $tabbg;
 }  }
   
 td.LC_zero_height {  
   line-height: 0;  
   cellpadding: 0;  
 }  
   
 table.LC_data_table {  table.LC_data_table {
   border: 1px solid #000000;    border: 1px solid #000000;
   border-collapse: separate;    border-collapse: separate;
Line 7294  table.LC_prior_tries td { Line 6657  table.LC_prior_tries td {
   padding: 6px;    padding: 6px;
 }  }
   
 .LC_answer_unknown,  .LC_answer_unknown {
 .LC_answer_warning {  
   background: orange;    background: orange;
   color: black;    color: black;
   padding: 6px;    padding: 6px;
Line 7377  table.LC_data_table tr > td.LC_docs_entr Line 6739  table.LC_data_table tr > td.LC_docs_entr
   color: #990000;    color: #990000;
 }  }
   
 .LC_domprefs_email,  
 .LC_docs_reinit_warn,  .LC_docs_reinit_warn,
 .LC_docs_ext_edit {  .LC_docs_ext_edit {
   font-size: x-small;    font-size: x-small;
Line 7674  ol.LC_primary_menu li { Line 7035  ol.LC_primary_menu li {
   line-height: 1.5em;    line-height: 1.5em;
 }  }
   
 ol.LC_primary_menu li a,   ol.LC_primary_menu li a,
 ol.LC_primary_menu li p {  ol.LC_primary_menu li p {
   display: block;    display: block;
   margin: 0;    margin: 0;
Line 7689  ol.LC_primary_menu li p span.LC_primary_ Line 7050  ol.LC_primary_menu li p span.LC_primary_
 }  }
   
 ol.LC_primary_menu li p span.LC_primary_menu_innerarrow {  ol.LC_primary_menu li p span.LC_primary_menu_innerarrow {
   display: inline-block;    display: inline-block;
   width: 5%;    width: 5%;
   float: right;    float: right;
   text-align: right;    text-align: right;
Line 7724  ol.LC_primary_menu li:hover li, ol.LC_pr Line 7085  ol.LC_primary_menu li:hover li, ol.LC_pr
   float: none;    float: none;
   border-left: 1px solid black;    border-left: 1px solid black;
   border-right: 1px solid black;    border-right: 1px solid black;
 /* A dark bottom border to visualize different menu options;  /* A dark bottom border to visualize different menu options; 
 overwritten in the create_submenu routine for the last border-bottom of the menu */  overwritten in the create_submenu routine for the last border-bottom of the menu */
   border-bottom: 1px solid $data_table_dark;    border-bottom: 1px solid $data_table_dark; 
 }  }
   
 ol.LC_primary_menu li li p:hover {  ol.LC_primary_menu li li p:hover {
Line 8169  a#LC_content_toolbar_edittoplevel { Line 7530  a#LC_content_toolbar_edittoplevel {
   background-image:url(/res/adm/pages/edittoplevel.gif);    background-image:url(/res/adm/pages/edittoplevel.gif);
 }  }
   
 a#LC_content_toolbar_printout {  
   background-image:url(/res/adm/pages/printout.gif);  
 }  
   
 ul#LC_toolbar li a:hover {  ul#LC_toolbar li a:hover {
   background-position: bottom center;    background-position: bottom center;
 }  }
Line 8290  ul.LC_funclist li { Line 7647  ul.LC_funclist li {
  cursor:pointer;   cursor:pointer;
 }  }
   
 .LCisDisabled {  /*
   cursor: not-allowed;    styles used for response display
   opacity: 0.5;  */
 }  div.LC_radiofoil, div.LC_rankfoil {
     margin: .5em 0em .5em 0em;
 a[aria-disabled="true"] {  
   color: currentColor;  
   display: inline-block;  /* For IE11/ MS Edge bug */  
   pointer-events: none;  
   text-decoration: none;  
 }  }
   table.LC_itemgroup {
 pre.LC_wordwrap {    margin-top: 1em;
   white-space: pre-wrap;  
   white-space: -moz-pre-wrap;  
   white-space: -pre-wrap;  
   white-space: -o-pre-wrap;  
   word-wrap: break-word;  
 }  }
   
 /*  /*
Line 8331  span.roman {font-family: serif; font-sty Line 7678  span.roman {font-family: serif; font-sty
 span.overacc2 {position: relative;  left: .8em; top: -1.2ex;}  span.overacc2 {position: relative;  left: .8em; top: -1.2ex;}
 span.overacc1 {position: relative;  left: .6em; top: -1.2ex;}  span.overacc1 {position: relative;  left: .6em; top: -1.2ex;}
   
 #LC_minitab_header {  /*
   float:left;    sections with roles, for content only
   width:100%;  */
   background:#DAE0D2 url("/res/adm/pages/minitabmenu_bg.gif") repeat-x bottom;  section[class^="role-"] {
   font-size:93%;    padding-left: 10px;
   line-height:normal;    padding-right: 5px;
   margin: 0.5em 0 0.5em 0;    margin-top: 8px;
 }    margin-bottom: 8px;
 #LC_minitab_header ul {    border: 1px solid #2A4;
   margin:0;    border-radius: 5px;
   padding:10px 10px 0;    box-shadow: 0px 1px 1px #BBB;
   list-style:none;  
 }  }
 #LC_minitab_header li {  section[class^="role-"]>h1 {
   float:left;    position: relative;
   background:url("/res/adm/pages/minitabmenu_left.gif") no-repeat left top;    margin: 0px;
   margin:0;    padding-top: 10px;
   padding:0 0 0 9px;    padding-left: 40px;
 }  }
 #LC_minitab_header a {  section[class^="role-"]>h1:before {
   display:block;    position: absolute;
   background:url("/res/adm/pages/minitabmenu_right.gif") no-repeat right top;    left: -5px;
   padding:5px 15px 4px 6px;    top: 5px;
 }  }
 #LC_minitab_header #LC_current_minitab {  section.role-activity>h1:before {
   background-image:url("/res/adm/pages/minitabmenu_left_on.gif");    content:url('/adm/daxe/images/section_icons/activity.png');
 }  }
 #LC_minitab_header #LC_current_minitab a {  section.role-advice>h1:before {
   background-image:url("/res/adm/pages/minitabmenu_right_on.gif");    content:url('/adm/daxe/images/section_icons/advice.png');
   padding-bottom:5px;  }
   section.role-bibliography>h1:before {
     content:url('/adm/daxe/images/section_icons/bibliography.png');
   }
   section.role-citation>h1:before {
     content:url('/adm/daxe/images/section_icons/citation.png');
   }
   section.role-conclusion>h1:before {
     content:url('/adm/daxe/images/section_icons/conclusion.png');
   }
   section.role-definition>h1:before {
     content:url('/adm/daxe/images/section_icons/definition.png');
   }
   section.role-demonstration>h1:before {
     content:url('/adm/daxe/images/section_icons/demonstration.png');
   }
   section.role-example>h1:before {
     content:url('/adm/daxe/images/section_icons/example.png');
   }
   section.role-explanation>h1:before {
     content:url('/adm/daxe/images/section_icons/explanation.png');
   }
   section.role-introduction>h1:before {
     content:url('/adm/daxe/images/section_icons/introduction.png');
   }
   section.role-method>h1:before {
     content:url('/adm/daxe/images/section_icons/method.png');
   }
   section.role-more_information>h1:before {
     content:url('/adm/daxe/images/section_icons/more_information.png');
   }
   section.role-objectives>h1:before {
     content:url('/adm/daxe/images/section_icons/objectives.png');
   }
   section.role-prerequisites>h1:before {
     content:url('/adm/daxe/images/section_icons/prerequisites.png');
   }
   section.role-remark>h1:before {
     content:url('/adm/daxe/images/section_icons/remark.png');
   }
   section.role-reminder>h1:before {
     content:url('/adm/daxe/images/section_icons/reminder.png');
   }
   section.role-summary>h1:before {
     content:url('/adm/daxe/images/section_icons/summary.png');
   }
   section.role-syntax>h1:before {
     content:url('/adm/daxe/images/section_icons/syntax.png');
   }
   section.role-warning>h1:before {
     content:url('/adm/daxe/images/section_icons/warning.png');
 }  }
   
   
 END  END
 }  }
Line 8384  Inputs: $title - optional title for the Line 7779  Inputs: $title - optional title for the
                                    3- whether the side effect should occur                                     3- whether the side effect should occur
                            (side effect of setting                              (side effect of setting 
                                $env{'internal.head.redirect'} to the url                                  $env{'internal.head.redirect'} to the url 
                                redirected to)                                 redirected too)
                                    4- whether the redirect target should be  
                                       the opener of the current (pop-up)  
                                       window (side effect of setting  
                                       $env{'internal.head.to_opener'} to  
                                       1, if true.  
                                    5- whether encrypt check should be skipped  
             domain         -> force to color decorate a page for a specific              domain         -> force to color decorate a page for a specific
                                domain                                 domain
             function       -> force usage of a specific rolish color scheme              function       -> force usage of a specific rolish color scheme
Line 8427  sub headtag { Line 7816  sub headtag {
     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'}
Line 8453  sub headtag { Line 7842  sub headtag {
         }          }
     }      }
     if (ref($args->{'redirect'})) {      if (ref($args->{'redirect'})) {
  my ($time,$url,$inhibit_continue,$to_opener,$skip_enc_check) = @{$args->{'redirect'}};   my ($time,$url,$inhibit_continue) = @{$args->{'redirect'}};
         if (!$skip_enc_check) {   $url = &Apache::lonenc::check_encrypt($url);
     $url = &Apache::lonenc::check_encrypt($url);  
         }  
  if (!$inhibit_continue) {   if (!$inhibit_continue) {
     $env{'internal.head.redirect'} = $url;      $env{'internal.head.redirect'} = $url;
  }   }
         $result.=<<"ADDMETA";   $result.=<<ADDMETA
 <meta http-equiv="pragma" content="no-cache" />  <meta http-equiv="pragma" content="no-cache" />
 ADDMETA  
         if ($to_opener) {  
             $env{'internal.head.to_opener'} = 1;  
             my $dest = &js_escape($url);  
             my $timeout = int($time * 1000);  
             $result .=<<"ENDJS";  
 <script type="text/javascript">  
 // <![CDATA[  
 function LC_To_Opener() {  
     var dest = '$dest';  
     if (dest != '') {  
         if (window.opener != null && !window.opener.closed) {  
             window.opener.location.href=dest;  
             window.close();  
         } else {  
             window.location.href=dest;  
         }  
     }  
 }  
 \$(document).ready(function () {  
     setTimeout('LC_To_Opener()',$timeout);  
 });  
 // ]]>  
 </script>  
 ENDJS  
         } else {  
             $result.=<<"ADDMETA";  
 <meta http-equiv="Refresh" content="$time; url=$url" />  <meta http-equiv="Refresh" content="$time; url=$url" />
 ADDMETA  ADDMETA
         }  
     } else {      } else {
         unless (($args->{'frameset'}) || ($args->{'js_ready'}) || ($args->{'only_body'}) || ($args->{'no_nav_bar'})) {          unless (($args->{'frameset'}) || ($args->{'js_ready'}) || ($args->{'only_body'}) || ($args->{'no_nav_bar'})) {
             my $requrl = $env{'request.uri'};              my $requrl = $env{'request.uri'};
Line 8505  ADDMETA Line 7864  ADDMETA
                 my $dom_in_use = $Apache::lonnet::perlvar{'lonDefDomain'};                  my $dom_in_use = $Apache::lonnet::perlvar{'lonDefDomain'};
                 unless (&Apache::lonnet::allowed('mau',$dom_in_use)) {                  unless (&Apache::lonnet::allowed('mau',$dom_in_use)) {
                     my %domdefs = &Apache::lonnet::get_domain_defaults($dom_in_use);                      my %domdefs = &Apache::lonnet::get_domain_defaults($dom_in_use);
                     my $lonhost = $Apache::lonnet::perlvar{'lonHostID'};  
                     my ($offload,$offloadoth);  
                     if (ref($domdefs{'offloadnow'}) eq 'HASH') {                      if (ref($domdefs{'offloadnow'}) eq 'HASH') {
                           my $lonhost = $Apache::lonnet::perlvar{'lonHostID'};
                         if ($domdefs{'offloadnow'}{$lonhost}) {                          if ($domdefs{'offloadnow'}{$lonhost}) {
                             $offload = 1;                              my $newserver = &Apache::lonnet::spareserver(30000,undef,1,$dom_in_use);
                             if (($env{'user.domain'} ne '') && ($env{'user.domain'} ne $dom_in_use) &&                              if (($newserver) && ($newserver ne $lonhost)) {
                                 (!(($env{'user.name'} eq 'public') && ($env{'user.domain'} eq 'public')))) {                                  my $numsec = 5;
                                 unless (&Apache::lonnet::shared_institution($env{'user.domain'})) {                                  my $timeout = $numsec * 1000;
                                     $offloadoth = 1;                                  my ($newurl,$locknum,%locks,$msg);
                                     $dom_in_use = $env{'user.domain'};                                  if ($env{'request.role.adv'}) {
                                       ($locknum,%locks) = &Apache::lonnet::get_locks();
                                 }                                  }
                             }                                  my $disable_submit = 0;
                         }                                  if ($requrl =~ /$LONCAPA::assess_re/) {
                     }                                      $disable_submit = 1;
                     unless ($offload) {  
                         if (ref($domdefs{'offloadoth'}) eq 'HASH') {  
                             if ($domdefs{'offloadoth'}{$lonhost}) {  
                                 if (($env{'user.domain'} ne '') && ($env{'user.domain'} ne $dom_in_use) &&  
                                     (!(($env{'user.name'} eq 'public') && ($env{'user.domain'} eq 'public')))) {  
                                     unless (&Apache::lonnet::shared_institution($env{'user.domain'})) {  
                                         $offload = 1;  
                                         $offloadoth = 1;  
                                         $dom_in_use = $env{'user.domain'};  
                                     }  
                                 }                                  }
                             }                                  if ($locknum) {
                         }                                      my @lockinfo = sort(values(%locks));
                     }                                      $msg = &mt('Once the following tasks are complete: ')."\\n".
                     if ($offload) {                                             join(", ",sort(values(%locks)))."\\n".
                         my $newserver = &Apache::lonnet::spareserver(undef,30000,undef,1,$dom_in_use);                                             &mt('your session will be transferred to a different server, after you click "Roles".');
                         if (($newserver eq '') && ($offloadoth)) {  
                             my @domains = &Apache::lonnet::current_machine_domains();  
                             if (($dom_in_use ne '') && (!grep(/^\Q$dom_in_use\E$/,@domains))) {  
                                 ($newserver) = &Apache::lonnet::choose_server($dom_in_use);  
                             }  
                         }  
                         if (($newserver) && ($newserver ne $lonhost)) {  
                             my $numsec = 5;  
                             my $timeout = $numsec * 1000;  
                             my ($newurl,$locknum,%locks,$msg);  
                             if ($env{'request.role.adv'}) {  
                                 ($locknum,%locks) = &Apache::lonnet::get_locks();  
                             }  
                             my $disable_submit = 0;  
                             if ($requrl =~ /$LONCAPA::assess_re/) {  
                                 $disable_submit = 1;  
                             }  
                             if ($locknum) {  
                                 my @lockinfo = sort(values(%locks));  
                                 $msg = &mt('Once the following tasks are complete:')." \n".  
                                        join(", ",sort(values(%locks)))."\n";  
                                 if (&show_course()) {  
                                     $msg .= &mt('your session will be transferred to a different server, after you click "Courses".');  
                                 } else {                                  } else {
                                     $msg .= &mt('your session will be transferred to a different server, after you click "Roles".');                                      if (($requrl =~ m{^/res/}) && ($env{'form.submitted'} =~ /^part_/)) {
                                 }                                          $msg = &mt('Your LON-CAPA submission has been recorded')."\\n";
                             } else {  
                                 if (($requrl =~ m{^/res/}) && ($env{'form.submitted'} =~ /^part_/)) {  
                                     $msg = &mt('Your LON-CAPA submission has been recorded')."\n";  
                                 }  
                                 $msg .= &mt('Your current LON-CAPA session will be transferred to a different server in [quant,_1,second].',$numsec);  
                                 $newurl = '/adm/switchserver?otherserver='.$newserver;  
                                 if (($env{'request.role'}) && ($env{'request.role'} ne 'cm')) {  
                                     $newurl .= '&role='.$env{'request.role'};  
                                 }  
                                 if ($env{'request.symb'}) {  
                                     my $shownsymb = &Apache::lonenc::check_encrypt($env{'request.symb'});  
                                     if ($shownsymb =~ m{^/enc/}) {  
                                         my $reqdmajor = 2;  
                                         my $reqdminor = 11;  
                                         my $reqdsubminor = 3;  
                                         my $newserverrev = &Apache::lonnet::get_server_loncaparev('',$newserver);  
                                         my $remoterev = &Apache::lonnet::get_server_loncaparev(undef,$newserver);  
                                         my ($major,$minor,$subminor) = ($remoterev =~ /^\'?(\d+)\.(\d+)\.(\d+|)[\w.\-]+\'?$/);  
                                         if (($major eq '' && $minor eq '') ||  
                                             (($reqdmajor > $major) || (($reqdmajor == $major) && ($reqdminor > $minor)) ||  
                                             (($reqdmajor == $major) && ($reqdminor == $minor) && (($subminor eq '') ||  
                                              ($reqdsubminor > $subminor))))) {  
                                             undef($shownsymb);  
                                         }  
                                     }                                      }
                                     if ($shownsymb) {                                      $msg .= &mt('Your current LON-CAPA session will be transferred to a different server in [quant,_1,second].',$numsec);
                                         &js_escape(\$shownsymb);                                      $newurl = '/adm/switchserver?otherserver='.$newserver;
                                         $newurl .= '&symb='.$shownsymb;                                      if (($env{'request.role'}) && ($env{'request.role'} ne 'cm')) {
                                           $newurl .= '&role='.$env{'request.role'};
                                       }
                                       if ($env{'request.symb'}) {
                                           $newurl .= '&symb='.$env{'request.symb'};
                                       } else {
                                           $newurl .= '&origurl='.$requrl;
                                     }                                      }
                                 } else {  
                                     my $shownurl = &Apache::lonenc::check_encrypt($requrl);  
                                     &js_escape(\$shownurl);  
                                     $newurl .= '&origurl='.$shownurl;  
                                 }                                  }
                             }                                  &js_escape(\$msg);
                             &js_escape(\$msg);                                  $result.=<<OFFLOAD
                             $result.=<<OFFLOAD  
 <meta http-equiv="pragma" content="no-cache" />  <meta http-equiv="pragma" content="no-cache" />
 <script type="text/javascript">  <script type="text/javascript">
 // <![CDATA[  // <![CDATA[
Line 8618  function LC_Offload_Now() { Line 7921  function LC_Offload_Now() {
 // ]]>  // ]]>
 </script>  </script>
 OFFLOAD  OFFLOAD
                               }
                         }                          }
                     }                      }
                 }                  }
Line 8633  OFFLOAD Line 7937  OFFLOAD
     if (!$args->{'frameset'}) {      if (!$args->{'frameset'}) {
         $result .= ' /';          $result .= ' /';
     }      }
     $result .= '>'      $result .= '>' 
         .$inhibitprint          .$inhibitprint
  .$head_extra;   .$head_extra;
     my $clientmobile;      if ($env{'browser.mobile'}) {
     if (($env{'user.name'} eq '') && ($env{'user.domain'} eq '')) {  
         (undef,undef,undef,undef,undef,undef,$clientmobile) = &decode_user_agent();  
     } else {  
         $clientmobile = $env{'browser.mobile'};  
     }  
     if ($clientmobile) {  
         $result .= '          $result .= '
 <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=0, minimum-scale=1.0, maximum-scale=1.0">  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=0, minimum-scale=1.0, maximum-scale=1.0">
 <meta name="apple-mobile-web-app-capable" content="yes" />';  <meta name="apple-mobile-web-app-capable" content="yes" />';
     }      }
     $result .= '<meta name="google" content="notranslate" />'."\n";  
     return $result.'</head>';      return $result.'</head>';
 }  }
   
Line 8666  sub font_settings { Line 7963  sub font_settings {
     my $headerstring='';      my $headerstring='';
     if ((!$env{'browser.mathml'} && $env{'browser.unicode'}) ||      if ((!$env{'browser.mathml'} && $env{'browser.unicode'}) ||
         ((ref($args) eq 'HASH') && ($args->{'browser.unicode'}))) {          ((ref($args) eq 'HASH') && ($args->{'browser.unicode'}))) {
  $headerstring.=          $headerstring.=
     '<meta http-equiv="Content-Type" content="text/html; charset=utf-8"';              '<meta http-equiv="Content-Type" content="text/html; charset=utf-8"';
         if (!$args->{'frameset'}) {          if (!$args->{'frameset'}) {
             $headerstring.= ' /';      $headerstring.= ' /';
         }          }
         $headerstring .= '>'."\n";   $headerstring .= '>'."\n";
     }      }
     return $headerstring;      return $headerstring;
 }  }
Line 8716  sub print_suppression { Line 8013  sub print_suppression {
         }          }
         my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};          my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
         my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};          my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
         my $clientip = &Apache::lonnet::get_requestor_ip();          my $blocked = &blocking_status('printout',$cnum,$cdom,undef,1);
         my $blocked = &blocking_status('printout',$clientip,$cnum,$cdom,undef,1);  
         if ($blocked) {          if ($blocked) {
             my $checkrole = "cm./$cdom/$cnum";              my $checkrole = "cm./$cdom/$cnum";
             if ($env{'request.course.sec'} ne '') {              if ($env{'request.course.sec'} ne '') {
Line 8825  $args - additional optional args support Line 8121  $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
              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
              bread_crumbs_nomenu -> if true will pass false as the value of $menulink               group          -> includes the current group, if page is for a 
                                     to lonhtmlcommon::breadcrumbs                                 specific group  
              group          -> includes the current group, if page is for a  
                                specific group  
              use_absolute   -> for request for external resource or syllabus, this  
                                will contain https://<hostname> if server uses  
                                https (as per hosts.tab), but request is for http  
              hostname       -> hostname, originally from $r->hostname(), (optional).  
              links_disabled -> Links in primary and secondary menus are disabled  
                                (Can enable them once page has loaded - see lonroles.pm  
                                for an example).  
              links_target   -> Target for links, e.g., _parent (optional).  
   
 =back  =back
   
Line 8854  sub start_page { Line 8138  sub start_page {
     #&Apache::lonnet::logthis("start_page ".join(':',caller(0)));      #&Apache::lonnet::logthis("start_page ".join(':',caller(0)));
   
     $env{'internal.start_page'}++;      $env{'internal.start_page'}++;
     my ($result,@advtools,$ltiscope,$ltiuri,%ltimenu,$menucoll,%menu);      my ($result,@advtools);
   
     if (! exists($args->{'skip_phases'}{'head'}) ) {      if (! exists($args->{'skip_phases'}{'head'}) ) {
         $result .= &xml_begin($args->{'frameset'}) . &headtag($title, $head_extra, $args);          $result .= &xml_begin($args->{'frameset'}) . &headtag($title, $head_extra, $args);
     }      }
       
     if (($env{'request.course.id'}) && ($env{'request.lti.login'})) {  
         if ($env{'course.'.$env{'request.course.id'}.'.lti.override'}) {  
             unless ($env{'course.'.$env{'request.course.id'}.'.lti.topmenu'}) {  
                 $args->{'no_primary_menu'} = 1;  
             }  
             unless ($env{'course.'.$env{'request.course.id'}.'.lti.inlinemenu'}) {  
                 $args->{'no_inline_menu'} = 1;  
             }  
             if ($env{'course.'.$env{'request.course.id'}.'.lti.lcmenu'}) {  
                 map { $ltimenu{$_} = 1; } split(/,/,$env{'course.'.$env{'request.course.id'}.'.lti.lcmenu'});  
             }  
         } else {  
             my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};  
             my %lti = &Apache::lonnet::get_domain_lti($cdom,'provider');  
             if (ref($lti{$env{'request.lti.login'}}) eq 'HASH') {  
                 unless ($lti{$env{'request.lti.login'}}{'topmenu'}) {  
                     $args->{'no_primary_menu'} = 1;  
                 }  
                 unless ($lti{$env{'request.lti.login'}}{'inlinemenu'}) {  
                     $args->{'no_inline_menu'} = 1;  
                 }  
                 if (ref($lti{$env{'request.lti.login'}}{'lcmenu'}) eq 'ARRAY') {  
                     map { $ltimenu{$_} = 1; } @{$lti{$env{'request.lti.login'}}{'lcmenu'}};  
                 }  
             }  
         }  
         ($ltiscope,$ltiuri) = &LONCAPA::ltiutils::lti_provider_scope($env{'request.lti.uri'},  
                                   $env{'course.'.$env{'request.course.id'}.'.domain'},  
                                   $env{'course.'.$env{'request.course.id'}.'.num'});  
     } elsif ($env{'request.course.id'}) {  
         my $expiretime=600;  
         if ((time-$env{'course.'.$env{'request.course.id'}.'.last_cache'}) > $expiretime) {  
             &Apache::lonnet::coursedescription($env{'request.course.id'},{'freshen_cache' => 1});  
         }  
         my ($deeplinkmenu,$menuref);  
         ($menucoll,$deeplinkmenu,$menuref) = &menucoll_in_effect();  
         if ($menucoll) {  
             if (ref($menuref) eq 'HASH') {  
                 %menu = %{$menuref};  
             }  
             if ($menu{'top'} eq 'n') {  
                 $args->{'no_primary_menu'} = 1;  
             }  
             if ($menu{'inline'} eq 'n') {  
                 unless (&Apache::lonnet::allowed('opa')) {  
                     my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};  
                     my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};  
                     my $crstype = &course_type();  
                     my $now = time;  
                     my $ccrole;  
                     if ($crstype eq 'Community') {  
                         $ccrole = 'co';  
                     } else {  
                         $ccrole = 'cc';  
                     }  
                     if ($env{'user.role.'.$ccrole.'./'.$cdom.'/'.$cnum}) {  
                         my ($start,$end) = split(/\./,$env{'user.role.'.$ccrole.'./'.$cdom.'/'.$cnum});  
                         if ((($start) && ($start<0)) ||  
                             (($end) && ($end<$now))  ||  
                             (($start) && ($now<$start))) {  
                             $args->{'no_inline_menu'} = 1;  
                         }  
                     } else {  
                         $args->{'no_inline_menu'} = 1;  
                     }  
                 }  
             }  
         }  
     }  
   
     my $showncrumbs;  
     if (! exists($args->{'skip_phases'}{'body'}) ) {      if (! exists($args->{'skip_phases'}{'body'}) ) {
  if ($args->{'frameset'}) {   if ($args->{'frameset'}) {
     my $attr_string = &make_attr_string($args->{'force_register'},      my $attr_string = &make_attr_string($args->{'force_register'},
Line 8942  sub start_page { Line 8155  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,                           \@advtools);
                          $ltiscope,$ltiuri,\%ltimenu,$menucoll,\%menu,\$showncrumbs);  
         }          }
     }      }
   
Line 8966  sub start_page { Line 8178  sub start_page {
   
     #Breadcrumbs      #Breadcrumbs
     if (exists($args->{'bread_crumbs'}) or exists($args->{'bread_crumbs_component'})) {      if (exists($args->{'bread_crumbs'}) or exists($args->{'bread_crumbs_component'})) {
         unless ($showncrumbs) {  
  &Apache::lonhtmlcommon::clear_breadcrumbs();   &Apache::lonhtmlcommon::clear_breadcrumbs();
  #if any br links exists, add them to the breadcrumbs   #if any br links exists, add them to the breadcrumbs
  if (exists($args->{'bread_crumbs'}) and ref($args->{'bread_crumbs'}) eq 'ARRAY') {            if (exists($args->{'bread_crumbs'}) and ref($args->{'bread_crumbs'}) eq 'ARRAY') {         
Line 8978  sub start_page { Line 8189  sub start_page {
                 if (@advtools > 0) {                  if (@advtools > 0) {
                     &Apache::lonmenu::advtools_crumbs(@advtools);                      &Apache::lonmenu::advtools_crumbs(@advtools);
                 }                  }
                 my $menulink;  
                 # if arg: bread_crumbs_nomenu is true pass 0 as $menulink item.  
                 if ((exists($args->{'bread_crumbs_nomenu'})) ||  
                     ($ltiscope eq 'map') || ($ltiscope eq 'resource')) {  
                     $menulink = 0;  
                 } else {  
                     undef($menulink);  
                 }  
                 my $linkprotout;  
                 if ($env{'request.deeplink.login'}) {  
                     my $linkprotout = &Apache::lonmenu::linkprot_exit();  
                     if ($linkprotout) {  
                         &Apache::lonhtmlcommon::add_breadcrumb_tool('tools',$linkprotout);  
                     }  
                 }  
  #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'})){
  $result .= &Apache::lonhtmlcommon::breadcrumbs($args->{'bread_crumbs_component'},'',$menulink);   $result .= &Apache::lonhtmlcommon::breadcrumbs($args->{'bread_crumbs_component'});
  } else {   }else{
  $result .= &Apache::lonhtmlcommon::breadcrumbs('','',$menulink);   $result .= &Apache::lonhtmlcommon::breadcrumbs();
  }   }
         }  
     } elsif (($env{'environment.remote'} eq 'on') &&  
              ($env{'form.inhibitmenu'} ne 'yes') &&  
              ($env{'request.noversionuri'} =~ m{^/res/}) &&  
              ($env{'request.noversionuri'} !~ m{^/res/adm/pages/})) {  
         $result .= '<div style="padding:0;margin:0;clear:both"><hr /></div>';  
     }      }
     return $result;      return $result;
 }  }
Line 9041  sub end_page { Line 8232  sub end_page {
     return $result;      return $result;
 }  }
   
 sub menucoll_in_effect {  
     my ($menucoll,$deeplinkmenu,%menu);  
     if ($env{'request.course.id'}) {  
         $menucoll = $env{'course.'.$env{'request.course.id'}.'.menudefault'};  
         if ($env{'request.deeplink.login'}) {  
             my ($deeplink_symb,$deeplink,$check_login_symb);  
             my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};  
             my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};  
             if ($env{'request.noversionuri'} =~ m{^/(res|uploaded)/}) {  
                 if ($env{'request.noversionuri'} =~ /\.(page|sequence)$/) {  
                     my $navmap = Apache::lonnavmaps::navmap->new();  
                     if (ref($navmap)) {  
                         $deeplink = $navmap->get_mapparam(undef,  
                                                           &Apache::lonnet::declutter($env{'request.noversionuri'}),  
                                                           '0.deeplink');  
                     } else {  
                         $check_login_symb = 1;  
                     }  
                 } else {  
                     my $symb=&Apache::lonnet::symbread();  
                     if ($symb) {  
                         $deeplink = &Apache::lonnet::EXT('resource.0.deeplink',$symb);  
                     } else {  
                         $check_login_symb = 1;  
                     }  
                 }  
             } else {  
                 $check_login_symb = 1;  
             }  
             if ($check_login_symb) {  
                 $deeplink_symb = &deeplink_login_symb($cnum,$cdom);  
                 if ($deeplink_symb =~ /\.(page|sequence)$/) {  
                     my $mapname = &Apache::lonnet::deversion((&Apache::lonnet::decode_symb($deeplink_symb))[2]);  
                     my $navmap = Apache::lonnavmaps::navmap->new();  
                     if (ref($navmap)) {  
                         $deeplink = $navmap->get_mapparam(undef,$mapname,'0.deeplink');  
                     }  
                 } else {  
                     $deeplink = &Apache::lonnet::EXT('resource.0.deeplink',$deeplink_symb);  
                 }  
             }  
             if ($deeplink ne '') {  
                 my ($state,$others,$listed,$scope,$protect,$display,$target) = split(/,/,$deeplink);  
                 if ($display =~ /^\d+$/) {  
                     $deeplinkmenu = 1;  
                     $menucoll = $display;  
                 }  
             }  
         }  
         if ($menucoll) {  
             %menu = &page_menu($env{'course.'.$env{'request.course.id'}.'.menucollections'},$menucoll);  
         }  
     }  
     return ($menucoll,$deeplinkmenu,\%menu);  
 }  
   
 sub deeplink_login_symb {  
     my ($cnum,$cdom) = @_;  
     my $login_symb;  
     if ($env{'request.deeplink.login'}) {  
         $login_symb = &symb_from_tinyurl($env{'request.deeplink.login'},$cnum,$cdom);  
     }  
     return $login_symb;  
 }  
   
 sub symb_from_tinyurl {  
     my ($url,$cnum,$cdom) = @_;  
     if ($url =~ m{^\Q/tiny/$cdom/\E(\w+)$}) {  
         my $key = $1;  
         my ($tinyurl,$login);  
         my ($result,$cached)=&Apache::lonnet::is_cached_new('tiny',$cdom."\0".$key);  
         if (defined($cached)) {  
             $tinyurl = $result;  
         } else {  
             my $configuname = &Apache::lonnet::get_domainconfiguser($cdom);  
             my %currtiny = &Apache::lonnet::get('tiny',[$key],$cdom,$configuname);  
             if ($currtiny{$key} ne '') {  
                 $tinyurl = $currtiny{$key};  
                 &Apache::lonnet::do_cache_new('tiny',$cdom."\0".$key,$currtiny{$key},600);  
             }  
         }  
         if ($tinyurl ne '') {  
             my ($cnumreq,$symb) = split(/\&/,$tinyurl);  
             if (wantarray) {  
                 return ($cnumreq,$symb);  
             } elsif ($cnumreq eq $cnum) {  
                 return $symb;  
             }  
         }  
     }  
     if (wantarray) {  
         return ();  
     } else {  
         return;  
     }  
 }  
   
 sub wishlist_window {  sub wishlist_window {
     return(<<'ENDWISHLIST');      return(<<'ENDWISHLIST');
 <script type="text/javascript">  <script type="text/javascript">
Line 9197  var modalWindow = { Line 8291  var modalWindow = {
 };  };
  var openMyModal = function(source,width,height,scrolling,transparency,style)   var openMyModal = function(source,width,height,scrolling,transparency,style)
  {   {
                 source = source.replace(/'/g,"&#39;");                  source = source.replace("'","&#39;");
  modalWindow.windowId = "myModal";   modalWindow.windowId = "myModal";
  modalWindow.width = width;   modalWindow.width = width;
  modalWindow.height = height;   modalWindow.height = height;
Line 9222  sub modal_link { Line 8316  sub modal_link {
         $target_attr = 'target="'.$target.'"';          $target_attr = 'target="'.$target.'"';
     }      }
     return <<"ENDLINK";      return <<"ENDLINK";
 <a href="$link" $target_attr title="$title" onclick="javascript:openMyModal('$link',$width,$height,'$scrolling','$transparency','$style'); return false;">$linktext</a>  <a href="$link" $target_attr title="$title" onclick="javascript:openMyModal('$link',$width,$height,'$scrolling','$transparency','$style'); return false;">
              $linktext</a>
 ENDLINK  ENDLINK
 }  }
   
 sub modal_adhoc_script {  sub modal_adhoc_script {
     my ($funcname,$width,$height,$content,$possmathjax)=@_;      my ($funcname,$width,$height,$content)=@_;
     my $mathjax;  
     if ($possmathjax) {  
         $mathjax = <<'ENDJAX';  
                if (typeof MathJax == 'object') {  
                    MathJax.Hub.Queue(["Typeset",MathJax.Hub]);  
                }  
 ENDJAX  
     }  
     return (<<ENDADHOC);      return (<<ENDADHOC);
 <script type="text/javascript">  <script type="text/javascript">
 // <![CDATA[  // <![CDATA[
Line 9246  ENDJAX Line 8333  ENDJAX
                 modalWindow.height = $height;                  modalWindow.height = $height;
                 modalWindow.content = '$content';                  modalWindow.content = '$content';
                 modalWindow.open();                  modalWindow.open();
                 $mathjax  
         };            };  
 // ]]>  // ]]>
 </script>  </script>
Line 9254  ENDADHOC Line 8340  ENDADHOC
 }  }
   
 sub modal_adhoc_inner {  sub modal_adhoc_inner {
     my ($funcname,$width,$height,$content,$possmathjax)=@_;      my ($funcname,$width,$height,$content)=@_;
     my $innerwidth=$width-20;      my $innerwidth=$width-20;
     $content=&js_ready(      $content=&js_ready(
                &start_page('Dialog',undef,{'only_body'=>1,'bgcolor'=>'#FFFFFF'}).                   &start_page('Dialog',undef,{'only_body'=>1,'bgcolor'=>'#FFFFFF'}).
                  &start_scrollbox($width.'px',$innerwidth.'px',$height.'px','myModal','#FFFFFF',undef,1).                   &start_scrollbox($width.'px',$innerwidth.'px',$height.'px','myModal','#FFFFFF',undef,1).
                  $content.                   $content.
                  &end_scrollbox().                   &end_scrollbox().
                  &end_page()                   &end_page()
              );               );
     return &modal_adhoc_script($funcname,$width,$height,$content,$possmathjax);      return &modal_adhoc_script($funcname,$width,$height,$content);
 }  }
   
 sub modal_adhoc_window {  sub modal_adhoc_window {
     my ($funcname,$width,$height,$content,$linktext,$possmathjax)=@_;      my ($funcname,$width,$height,$content,$linktext)=@_;
     return &modal_adhoc_inner($funcname,$width,$height,$content,$possmathjax).      return &modal_adhoc_inner($funcname,$width,$height,$content).
            "<a href=\"javascript:$funcname();void(0);\">".$linktext."</a>";             "<a href=\"javascript:$funcname();void(0);\">".$linktext."</a>";
 }  }
   
Line 9334  sub end_togglebox { Line 8420  sub end_togglebox {
 }  }
   
 sub LCprogressbar_script {  sub LCprogressbar_script {
    my ($id,$number_to_do)=@_;     my ($id)=@_;
    if ($number_to_do) {     return(<<ENDPROGRESS);
        return(<<ENDPROGRESS);  
 <script type="text/javascript">  <script type="text/javascript">
 // <![CDATA[  // <![CDATA[
 \$('#progressbar$id').progressbar({  \$('#progressbar$id').progressbar({
Line 9349  sub LCprogressbar_script { Line 8434  sub LCprogressbar_script {
 // ]]>  // ]]>
 </script>  </script>
 ENDPROGRESS  ENDPROGRESS
    } else {  
        return(<<ENDPROGRESS);  
 <script type="text/javascript">  
 // <![CDATA[  
 \$('#progressbar$id').progressbar({  
   value: false,  
   create: function(event, ui) {  
     \$('.ui-widget-header', this).css({'background':'#F0F0F0'});  
     \$('.ui-progressbar-overlay', this).css({'margin':'0'});  
   }  
 });  
 // ]]>  
 </script>  
 ENDPROGRESS  
    }  
 }  }
   
 sub LCprogressbarUpdate_script {  sub LCprogressbarUpdate_script {
    return(<<ENDPROGRESSUPDATE);     return(<<ENDPROGRESSUPDATE);
 <style type="text/css">  <style type="text/css">
 .ui-progressbar { position:relative; }  .ui-progressbar { position:relative; }
 .progress-label {position: absolute; width: 100%; text-align: center; top: 1px; font-weight: bold; text-shadow: 1px 1px 0 #fff;margin: 0; line-height: 200%; }  
 .pblabel { position: absolute; width: 100%; text-align: center; line-height: 1.9em; }  .pblabel { position: absolute; width: 100%; text-align: center; line-height: 1.9em; }
 </style>  </style>
 <script type="text/javascript">  <script type="text/javascript">
 // <![CDATA[  // <![CDATA[
 var LCprogressTxt='---';  var LCprogressTxt='---';
   
 function LCupdateProgress(percent,progresstext,id,maxnum) {  function LCupdateProgress(percent,progresstext,id) {
    LCprogressTxt=progresstext;     LCprogressTxt=progresstext;
    if ((maxnum == '') || (maxnum == undefined) || (maxnum == null)) {     \$('#progressbar'+id).progressbar('value',percent);
        \$('#progressbar'+id).find('.progress-label').text(LCprogressTxt);  
    } else if (percent === \$('#progressbar'+id).progressbar( "value" )) {  
        \$('#progressbar'+id).find('.pblabel').text(LCprogressTxt);  
    } else {  
        \$('#progressbar'+id).progressbar('value',percent);  
    }  
 }  }
 // ]]>  // ]]>
 </script>  </script>
Line 9397  my $LCidcnt; Line 8460  my $LCidcnt;
 my $LCcurrentid;  my $LCcurrentid;
   
 sub LCprogressbar {  sub LCprogressbar {
     my ($r,$number_to_do,$preamble)=@_;      my ($r)=(@_);
     $LClastpercent=0;      $LClastpercent=0;
     $LCidcnt++;      $LCidcnt++;
     $LCcurrentid=$$.'_'.$LCidcnt;      $LCcurrentid=$$.'_'.$LCidcnt;
     my ($starting,$content);      my $starting=&mt('Starting');
     if ($number_to_do) {      my $content=(<<ENDPROGBAR);
         $starting=&mt('Starting');  
         $content=(<<ENDPROGBAR);  
 $preamble  
   <div id="progressbar$LCcurrentid">    <div id="progressbar$LCcurrentid">
     <span class="pblabel">$starting</span>      <span class="pblabel">$starting</span>
   </div>    </div>
 ENDPROGBAR  ENDPROGBAR
     } else {      &r_print($r,$content.&LCprogressbar_script($LCcurrentid));
         $starting=&mt('Loading...');  
         $LClastpercent='false';  
         $content=(<<ENDPROGBAR);  
 $preamble  
   <div id="progressbar$LCcurrentid">  
       <div class="progress-label">$starting</div>  
   </div>  
 ENDPROGBAR  
     }  
     &r_print($r,$content.&LCprogressbar_script($LCcurrentid,$number_to_do));  
 }  }
   
 sub LCprogressbarUpdate {  sub LCprogressbarUpdate {
     my ($r,$val,$text,$number_to_do)=@_;      my ($r,$val,$text)=@_;
     if ($number_to_do) {      unless ($val) { 
         unless ($val) {          if ($LClastpercent) {
             if ($LClastpercent) {             $val=$LClastpercent;
                 $val=$LClastpercent;         } else {
             } else {             $val=0;
                 $val=0;         }
             }  
         }  
         if ($val<0) { $val=0; }  
         if ($val>100) { $val=0; }  
         $LClastpercent=$val;  
         unless ($text) { $text=$val.'%'; }  
     } else {  
         $val = 'false';  
     }      }
       if ($val<0) { $val=0; }
       if ($val>100) { $val=0; }
       $LClastpercent=$val;
       unless ($text) { $text=$val.'%'; }
     $text=&js_ready($text);      $text=&js_ready($text);
     &r_print($r,<<ENDUPDATE);      &r_print($r,<<ENDUPDATE);
 <script type="text/javascript">  <script type="text/javascript">
 // <![CDATA[  // <![CDATA[
 LCupdateProgress($val,'$text','$LCcurrentid','$number_to_do');  LCupdateProgress($val,'$text','$LCcurrentid');
 // ]]>  // ]]>
 </script>  </script>
 ENDUPDATE  ENDUPDATE
Line 9629  function expand_div(caller) { Line 8675  function expand_div(caller) {
   
 sub simple_error_page {  sub simple_error_page {
     my ($r,$title,$msg,$args) = @_;      my ($r,$title,$msg,$args) = @_;
     my %displayargs;  
     if (ref($args) eq 'HASH') {      if (ref($args) eq 'HASH') {
         if (!$args->{'no_auto_mt_msg'}) { $msg = &mt($msg); }          if (!$args->{'no_auto_mt_msg'}) { $msg = &mt($msg); }
         if ($args->{'only_body'}) {  
             $displayargs{'only_body'} = 1;  
         }  
         if ($args->{'no_nav_bar'}) {  
             $displayargs{'no_nav_bar'} = 1;  
         }  
     } else {      } else {
         $msg = &mt($msg);          $msg = &mt($msg);
     }      }
   
     my $page =      my $page =
  &Apache::loncommon::start_page($title,'',\%displayargs).   &Apache::loncommon::start_page($title).
  '<p class="LC_error">'.$msg.'</p>'.   '<p class="LC_error">'.$msg.'</p>'.
  &Apache::loncommon::end_page();   &Apache::loncommon::end_page();
     if (ref($r)) {      if (ref($r)) {
Line 9949  sub get_sections { Line 8988  sub get_sections {
         }          }
     }      }
   
     if ($check_students) {      if ($check_students) { 
  my ($classlist) = &Apache::loncoursedata::get_classlist($cdom,$cnum);   my ($classlist) = &Apache::loncoursedata::get_classlist($cdom,$cnum);
  my $sec_index = &Apache::loncoursedata::CL_SECTION();   my $sec_index = &Apache::loncoursedata::CL_SECTION();
  my $status_index = &Apache::loncoursedata::CL_STATUS();   my $status_index = &Apache::loncoursedata::CL_STATUS();
Line 10345  sub get_user_quota { Line 9384  sub get_user_quota {
         if ($quota eq '' || wantarray) {          if ($quota eq '' || wantarray) {
             if ($quotaname eq 'course') {              if ($quotaname eq 'course') {
                 my %domdefs = &Apache::lonnet::get_domain_defaults($udom);                  my %domdefs = &Apache::lonnet::get_domain_defaults($udom);
                 if (($crstype eq 'official') || ($crstype eq 'unofficial') ||                  if (($crstype eq 'official') || ($crstype eq 'unofficial') || 
                     ($crstype eq 'community') || ($crstype eq 'textbook')) {                      ($crstype eq 'community') || ($crstype eq 'textbook')) { 
                     $defquota = $domdefs{$crstype.'quota'};                      $defquota = $domdefs{$crstype.'quota'};
                 }                  }
                 if ($defquota eq '') {                  if ($defquota eq '') {
Line 10530  sub excess_filesize_warning { Line 9569  sub excess_filesize_warning {
 ###############################################  ###############################################
   
   
   
   
 sub get_secgrprole_info {  sub get_secgrprole_info {
     my ($cdom,$cnum,$needroles,$type)  = @_;      my ($cdom,$cnum,$needroles,$type)  = @_;
     my %sections_count = &get_sections($cdom,$cnum);      my %sections_count = &get_sections($cdom,$cnum);
Line 10568  sub get_secgrprole_info { Line 9609  sub get_secgrprole_info {
 }  }
   
 sub user_picker {  sub user_picker {
     my ($dom,$srch,$forcenewuser,$caller,$cancreate,$usertype,$context,$fixeddom,$noinstd) = @_;      my ($dom,$srch,$forcenewuser,$caller,$cancreate,$usertype,$context) = @_;
     my $currdom = $dom;      my $currdom = $dom;
     my @alldoms = &Apache::lonnet::all_domains();  
     if (@alldoms == 1) {  
         my %domsrch = &Apache::lonnet::get_dom('configuration',  
                                                ['directorysrch'],$alldoms[0]);  
         my $domdesc = &Apache::lonnet::domain($alldoms[0],'description');  
         my $showdom = $domdesc;  
         if ($showdom eq '') {  
             $showdom = $dom;  
         }  
         if (ref($domsrch{'directorysrch'}) eq 'HASH') {  
             if ((!$domsrch{'directorysrch'}{'available'}) &&  
                 ($domsrch{'directorysrch'}{'lcavailable'} eq '0')) {  
                 return (&mt('LON-CAPA directory search is not available in domain: [_1]',$showdom),0);  
             }  
         }  
     }  
     my %curr_selected = (      my %curr_selected = (
                         srchin => 'dom',                          srchin => 'dom',
                         srchby => 'lastname',                          srchby => 'lastname',
Line 10632  sub user_picker { Line 9657  sub user_picker {
                                        );                                         );
     &html_escape(\%html_lt);      &html_escape(\%html_lt);
     &js_escape(\%js_lt);      &js_escape(\%js_lt);
     my $domform;      my $domform = &select_dom_form($currdom,'srchdomain',1,1);
     my $allow_blank = 1;  
     if ($fixeddom) {  
         $allow_blank = 0;  
         $domform = &select_dom_form($currdom,'srchdomain',$allow_blank,1,undef,[$currdom]);  
     } else {  
         $domform = &select_dom_form($currdom,'srchdomain',$allow_blank,1);  
     }  
     my $srchinsel = ' <select name="srchin">';      my $srchinsel = ' <select name="srchin">';
   
     my @srchins = ('crs','dom','alc','instd');      my @srchins = ('crs','dom','alc','instd');
Line 10651  sub user_picker { Line 9669  sub user_picker {
         next if ($option eq 'alc');          next if ($option eq 'alc');
         next if (($option eq 'crs') && ($env{'form.form'} eq 'requestcrs'));            next if (($option eq 'crs') && ($env{'form.form'} eq 'requestcrs'));  
         next if ($option eq 'crs' && !$env{'request.course.id'});          next if ($option eq 'crs' && !$env{'request.course.id'});
         next if (($option eq 'instd') && ($noinstd));  
         if ($curr_selected{'srchin'} eq $option) {          if ($curr_selected{'srchin'} eq $option) {
             $srchinsel .= '               $srchinsel .= ' 
    <option value="'.$option.'" selected="selected">'.$html_lt{$option}.'</option>';     <option value="'.$option.'" selected="selected">'.$html_lt{$option}.'</option>';
Line 10834  END_BLOCK Line 9851  END_BLOCK
                &Apache::lonhtmlcommon::row_closure(1)                 &Apache::lonhtmlcommon::row_closure(1)
                &Apache::lonhtmlcommon::end_pick_box().                 &Apache::lonhtmlcommon::end_pick_box().
                '<br />';                 '<br />';
     return ($output,1);      return $output;
 }  }
   
 sub user_rule_check {  sub user_rule_check {
Line 10843  sub user_rule_check { Line 9860  sub user_rule_check {
     if (ref($usershash) eq 'HASH') {      if (ref($usershash) eq 'HASH') {
         if (keys(%{$usershash}) > 1) {          if (keys(%{$usershash}) > 1) {
             my (%by_username,%by_id,%userdoms);              my (%by_username,%by_id,%userdoms);
             my $checkid;              my $checkid; 
             if (ref($checks) eq 'HASH') {              if (ref($checks) eq 'HASH') {
                 if ((!defined($checks->{'username'})) && (defined($checks->{'id'}))) {                  if ((!defined($checks->{'username'})) && (defined($checks->{'id'}))) {
                     $checkid = 1;                      $checkid = 1;
Line 10854  sub user_rule_check { Line 9871  sub user_rule_check {
                 if ($checkid) {                  if ($checkid) {
                     if (ref($usershash->{$user}) eq 'HASH') {                      if (ref($usershash->{$user}) eq 'HASH') {
                         if ($usershash->{$user}->{'id'} ne '') {                          if ($usershash->{$user}->{'id'} ne '') {
                             $by_id{$udom}{$usershash->{$user}->{'id'}} = $uname;                              $by_id{$udom}{$usershash->{$user}->{'id'}} = $uname; 
                             $userdoms{$udom} = 1;                              $userdoms{$udom} = 1;
                             if (ref($inst_results) eq 'HASH') {                              if (ref($inst_results) eq 'HASH') {
                                 $inst_results->{$uname.':'.$udom} = {};                                  $inst_results->{$uname.':'.$udom} = {};
Line 10924  sub user_rule_check { Line 9941  sub user_rule_check {
                 if (ref($usershash->{$user}) eq 'HASH') {                  if (ref($usershash->{$user}) eq 'HASH') {
                     if (ref($checks) eq 'HASH') {                      if (ref($checks) eq 'HASH') {
                         if (defined($checks->{'username'})) {                          if (defined($checks->{'username'})) {
                             ($inst_response{$user},%{$inst_results->{$user}}) =                              ($inst_response{$user},%{$inst_results->{$user}}) = 
                                 &Apache::lonnet::get_instuser($udom,$uname);                                  &Apache::lonnet::get_instuser($udom,$uname);
                         } elsif (defined($checks->{'id'})) {                          } elsif (defined($checks->{'id'})) {
                             if ($usershash->{$user}->{'id'} ne '') {                              if ($usershash->{$user}->{'id'} ne '') {
Line 10947  sub user_rule_check { Line 9964  sub user_rule_check {
                         if (ref($domconfig{'usercreation'}) eq 'HASH') {                          if (ref($domconfig{'usercreation'}) eq 'HASH') {
                             foreach my $item ('username','id') {                              foreach my $item ('username','id') {
                                 if (ref($domconfig{'usercreation'}{$item.'_rule'}) eq 'ARRAY') {                                  if (ref($domconfig{'usercreation'}{$item.'_rule'}) eq 'ARRAY') {
                                    $$curr_rules{$udom}{$item} =                                     $$curr_rules{$udom}{$item} = 
                                        $domconfig{'usercreation'}{$item.'_rule'};                                         $domconfig{'usercreation'}{$item.'_rule'};
                                 }                                  }
                             }                              }
Line 10970  sub user_rule_check { Line 9987  sub user_rule_check {
                     $id = $inst_results->{$user}->{'id'};                      $id = $inst_results->{$user}->{'id'};
                 }                  }
             }              }
             if ($id eq '') {              if ($id eq '') { 
                 if (ref($usershash->{$user})) {                  if (ref($usershash->{$user})) {
                     $id = $usershash->{$user}->{'id'};                      $id = $usershash->{$user}->{'id'};
                 }                  }
Line 11131  sub sorted_inst_types { Line 10148  sub sorted_inst_types {
 }  }
   
 sub get_institutional_codes {  sub get_institutional_codes {
     my ($cdom,$crs,$settings,$allcourses,$LC_code) = @_;      my ($settings,$allcourses,$LC_code) = @_;
 # Get complete list of course sections to update  # Get complete list of course sections to update
     my @currsections = ();      my @currsections = ();
     my @currxlists = ();      my @currxlists = ();
     my (%unclutteredsec,%unclutteredlcsec);  
     my $coursecode = $$settings{'internal.coursecode'};      my $coursecode = $$settings{'internal.coursecode'};
     my $crskey = $crs.':'.$coursecode;  
     @{$unclutteredsec{$crskey}} = ();  
     @{$unclutteredlcsec{$crskey}} = ();  
   
     if ($$settings{'internal.sectionnums'} ne '') {      if ($$settings{'internal.sectionnums'} ne '') {
         @currsections = split(/,/,$$settings{'internal.sectionnums'});          @currsections = split(/,/,$$settings{'internal.sectionnums'});
Line 11150  sub get_institutional_codes { Line 10163  sub get_institutional_codes {
     }      }
   
     if (@currxlists > 0) {      if (@currxlists > 0) {
         foreach my $xl (@currxlists) {          foreach (@currxlists) {
             if ($xl =~ /^([^:]+):(\w*)$/) {              if (m/^([^:]+):(\w*)$/) {
                 unless (grep/^$1$/,@{$allcourses}) {                  unless (grep/^$1$/,@{$allcourses}) {
                     push(@{$allcourses},$1);                      push @{$allcourses},$1;
                     $$LC_code{$1} = $2;                      $$LC_code{$1} = $2;
                 }                  }
             }              }
         }          }
     }      }
    
     if (@currsections > 0) {      if (@currsections > 0) {
         foreach my $sec (@currsections) {          foreach (@currsections) {
             if ($sec =~ m/^(\w+):(\w*)$/ ) {              if (m/^(\w+):(\w*)$/) {
                 my $instsec = $1;                  my $sec = $coursecode.$1;
                 my $lc_sec = $2;                  my $lc_sec = $2;
                 unless (grep/^\Q$instsec\E$/,@{$unclutteredsec{$crskey}}) {                  unless (grep/^$sec$/,@{$allcourses}) {
                     push(@{$unclutteredsec{$crskey}},$instsec);                      push @{$allcourses},$sec;
                     push(@{$unclutteredlcsec{$crskey}},$lc_sec);                      $$LC_code{$sec} = $lc_sec;
                 }  
             }  
         }  
     }  
   
     if (@{$unclutteredsec{$crskey}} > 0) {  
         my %formattedsec = &Apache::lonnet::auto_instsec_reformat($cdom,'clutter',\%unclutteredsec);  
         if ((ref($formattedsec{$crskey}) eq 'ARRAY') && (ref($unclutteredlcsec{$crskey}) eq 'ARRAY')) {  
             for (my $i=0; $i<@{$formattedsec{$crskey}}; $i++) {  
                 my $sec = $coursecode.$formattedsec{$crskey}[$i];  
                 unless (grep/^\Q$sec\E$/,@{$allcourses}) {  
                     push(@{$allcourses},$sec);  
                     $$LC_code{$sec} = $unclutteredlcsec{$crskey}[$i];  
                 }                  }
             }              }
         }          }
Line 11277  reservable_now - ref to hash of student_ Line 10277  reservable_now - ref to hash of student_
   
     Keys in inner hash are:      Keys in inner hash are:
     (a) symb: either blank or symb to which slot use is restricted.      (a) symb: either blank or symb to which slot use is restricted.
     (b) endreserve: end date of reservation period.      (b) endreserve: end date of reservation period. 
     (c) uniqueperiod: start,end dates when slot is to be uniquely  
         selected.  
   
 sorted_future - ref to array of student_schedulable slots reservable in  sorted_future - ref to array of student_schedulable slots reservable in
                 the future, ordered by start date of reservation period.                  the future, ordered by start date of reservation period.
Line 11290  future_reservable - ref to hash of stude Line 10288  future_reservable - ref to hash of stude
     Keys in inner hash are:      Keys in inner hash are:
     (a) symb: either blank or symb to which slot use is restricted.      (a) symb: either blank or symb to which slot use is restricted.
     (b) startreserve:  start date of reservation period.      (b) startreserve:  start date of reservation period.
     (c) uniqueperiod: start,end dates when slot is to be uniquely  
         selected.  
   
 =back  =back
   
Line 11299  future_reservable - ref to hash of stude Line 10295  future_reservable - ref to hash of stude
   
 sub get_future_slots {  sub get_future_slots {
     my ($cnum,$cdom,$now,$symb) = @_;      my ($cnum,$cdom,$now,$symb) = @_;
       my $map;
       if ($symb) {
           ($map) = &Apache::lonnet::decode_symb($symb);
       }
     my (%reservable_now,%future_reservable,@sorted_reservable,@sorted_future);      my (%reservable_now,%future_reservable,@sorted_reservable,@sorted_future);
     my %slots = &Apache::lonnet::get_course_slots($cnum,$cdom);      my %slots = &Apache::lonnet::get_course_slots($cnum,$cdom);
     foreach my $slot (keys(%slots)) {      foreach my $slot (keys(%slots)) {
         next unless($slots{$slot}->{'type'} eq 'schedulable_student');          next unless($slots{$slot}->{'type'} eq 'schedulable_student');
         if ($symb) {          if ($symb) {
             next if (($slots{$slot}->{'symb'} ne '') &&               if ($slots{$slot}->{'symb'} ne '') {
                      ($slots{$slot}->{'symb'} ne $symb));                  my $canuse;
                   my %oksymbs;
                   my @slotsymbs = split(/\s*,\s*/,$slots{$slot}->{'symb'});
                   map { $oksymbs{$_} = 1; } @slotsymbs;
                   if ($oksymbs{$symb}) {
                       $canuse = 1;
                   } else {
                       foreach my $item (@slotsymbs) {
                           if ($item =~ /\.(page|sequence)$/) {
                               (undef,undef,my $sloturl) = &Apache::lonnet::decode_symb($item);
                               if (($map ne '') && ($map eq $sloturl)) {
                                   $canuse = 1;
                                   last;
                               }
                           }
                       }
                   }
                   next unless ($canuse);
               }
         }          }
         if (($slots{$slot}->{'starttime'} > $now) &&          if (($slots{$slot}->{'starttime'} > $now) &&
             ($slots{$slot}->{'endtime'} > $now)) {              ($slots{$slot}->{'endtime'} > $now)) {
Line 11345  sub get_future_slots { Line 10363  sub get_future_slots {
             my $startreserve = $slots{$slot}->{'startreserve'};              my $startreserve = $slots{$slot}->{'startreserve'};
             my $endreserve = $slots{$slot}->{'endreserve'};              my $endreserve = $slots{$slot}->{'endreserve'};
             my $symb = $slots{$slot}->{'symb'};              my $symb = $slots{$slot}->{'symb'};
             my $uniqueperiod;  
             if (ref($slots{$slot}->{'uniqueperiod'}) eq 'ARRAY') {  
                 $uniqueperiod = join(',',@{$slots{$slot}->{'uniqueperiod'}});  
             }  
             if (($startreserve < $now) &&              if (($startreserve < $now) &&
                 (!$endreserve || $endreserve > $now)) {                  (!$endreserve || $endreserve > $now)) {
                 my $lastres = $endreserve;                  my $lastres = $endreserve;
Line 11357  sub get_future_slots { Line 10371  sub get_future_slots {
                 }                  }
                 $reservable_now{$slot} = {                  $reservable_now{$slot} = {
                                            symb       => $symb,                                             symb       => $symb,
                                            endreserve => $lastres,                                             endreserve => $lastres
                                            uniqueperiod => $uniqueperiod,     
                                          };                                           };
             } elsif (($startreserve > $now) &&              } elsif (($startreserve > $now) &&
                      (!$endreserve || $endreserve > $startreserve)) {                       (!$endreserve || $endreserve > $startreserve)) {
                 $future_reservable{$slot} = {                  $future_reservable{$slot} = {
                                               symb         => $symb,                                                symb         => $symb,
                                               startreserve => $startreserve,                                                startreserve => $startreserve
                                               uniqueperiod => $uniqueperiod,  
                                             };                                              };
             }              }
         }          }
Line 11546  sub ask_for_embedded_content { Line 10558  sub ask_for_embedded_content {
         $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};          $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
         $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};          $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
     }      }
     if (($actionurl eq '/adm/portfolio') ||      if (($actionurl eq '/adm/portfolio') || 
         ($actionurl eq '/adm/coursegrp_portfolio')) {          ($actionurl eq '/adm/coursegrp_portfolio')) {
         my $current_path='/';          my $current_path='/';
         if ($env{'form.currentpath'}) {          if ($env{'form.currentpath'}) {
Line 11578  sub ask_for_embedded_content { Line 10590  sub ask_for_embedded_content {
             $toplevel = $url;              $toplevel = $url;
             if ($args->{'context'} eq 'paste') {              if ($args->{'context'} eq 'paste') {
                 ($cdom,$cnum) = ($url =~ m{^\Q/uploaded/\E($match_domain)/($match_courseid)/});                  ($cdom,$cnum) = ($url =~ m{^\Q/uploaded/\E($match_domain)/($match_courseid)/});
                 ($path) =                  ($path) = 
                     ($toplevel =~ m{^(\Q/uploaded/$cdom/$cnum/\E(?:docs|supplemental)/(?:default|\d+)/\d+)/});                      ($toplevel =~ m{^(\Q/uploaded/$cdom/$cnum/\E(?:docs|supplemental)/(?:default|\d+)/\d+)/});
                 $fileloc = &Apache::lonnet::filelocation('',$toplevel);                  $fileloc = &Apache::lonnet::filelocation('',$toplevel);
                 $fileloc =~ s{^/}{};                  $fileloc =~ s{^/}{};
             }              }
         }          }
     } elsif ($actionurl eq '/adm/dependencies') {      } elsif ($actionurl eq '/adm/dependencies')  {
         if ($env{'request.course.id'} ne '') {          if ($env{'request.course.id'} ne '') {
             if (ref($args) eq 'HASH') {              if (ref($args) eq 'HASH') {
                 $url = $args->{'docs_url'};                  $url = $args->{'docs_url'};
                 $title = $args->{'docs_title'};                  $title = $args->{'docs_title'};
                 $toplevel = $url;                  $toplevel = $url; 
                 unless ($toplevel =~ m{^/}) {                  unless ($toplevel =~ m{^/}) {
                     $toplevel = "/$url";                      $toplevel = "/$url";
                 }                  }
Line 11668  sub ask_for_embedded_content { Line 10680  sub ask_for_embedded_content {
     my $dirptr = 16384;      my $dirptr = 16384;
     foreach my $path (keys(%subdependencies)) {      foreach my $path (keys(%subdependencies)) {
         $currsubfile{$path} = {};          $currsubfile{$path} = {};
         if (($actionurl eq '/adm/portfolio') ||          if (($actionurl eq '/adm/portfolio') || 
             ($actionurl eq '/adm/coursegrp_portfolio')) {               ($actionurl eq '/adm/coursegrp_portfolio')) {
             my ($sublistref,$listerror) =              my ($sublistref,$listerror) =
                 &Apache::lonnet::dirlist($url.$path,$udom,$uname,$getpropath);                  &Apache::lonnet::dirlist($url.$path,$udom,$uname,$getpropath);
             if (ref($sublistref) eq 'ARRAY') {              if (ref($sublistref) eq 'ARRAY') {
Line 11811  sub ask_for_embedded_content { Line 10823  sub ask_for_embedded_content {
         $counter = scalar(keys(%existing));          $counter = scalar(keys(%existing));
         $numpathchg = scalar(keys(%pathchanges));          $numpathchg = scalar(keys(%pathchanges));
         return ($output,$counter,$numpathchg,\%existing);          return ($output,$counter,$numpathchg,\%existing);
     } elsif (($actionurl eq "/public/$cdom/$cnum/syllabus") &&      } elsif (($actionurl eq "/public/$cdom/$cnum/syllabus") && 
              (ref($args) eq 'HASH') && ($args->{'context'} eq 'rewrites')) {               (ref($args) eq 'HASH') && ($args->{'context'} eq 'rewrites')) {
         $counter = scalar(keys(%existing));          $counter = scalar(keys(%existing));
         $numpathchg = scalar(keys(%pathchanges));          $numpathchg = scalar(keys(%pathchanges));
Line 12040  sub ask_for_embedded_content { Line 11052  sub ask_for_embedded_content {
   
 Performs clean-up of directories, subdirectories and filename in an  Performs clean-up of directories, subdirectories and filename in an
 embedded object, referenced in an HTML file which is being uploaded  embedded object, referenced in an HTML file which is being uploaded
 to a course or portfolio, where  to a course or portfolio, where 
 "Upload embedded images/multimedia files if HTML file" checkbox was  "Upload embedded images/multimedia files if HTML file" checkbox was
 checked.  checked.
   
Line 12059  sub clean_path { Line 11071  sub clean_path {
         @contents = ($embed_file);          @contents = ($embed_file);
     }      }
     my $lastidx = scalar(@contents)-1;      my $lastidx = scalar(@contents)-1;
     for (my $i=0; $i<=$lastidx; $i++) {      for (my $i=0; $i<=$lastidx; $i++) { 
         $contents[$i]=~s{\\}{/}g;          $contents[$i]=~s{\\}{/}g;
         $contents[$i]=~s/\s+/\_/g;          $contents[$i]=~s/\s+/\_/g;
         $contents[$i]=~s{[^/\w\.\-]}{}g;          $contents[$i]=~s{[^/\w\.\-]}{}g;
Line 12398  sub modify_html_refs { Line 11410  sub modify_html_refs {
     }      }
     my (%allfiles,%codebase,$output,$content);      my (%allfiles,%codebase,$output,$content);
     my @changes = &get_env_multiple('form.namechange');      my @changes = &get_env_multiple('form.namechange');
     unless ((@changes > 0)  || ($context eq 'syllabus')) {      unless ((@changes > 0) || ($context eq 'syllabus')) {
         if (wantarray) {          if (wantarray) {
             return ('',0,0);               return ('',0,0); 
         } else {          } else {
Line 12430  sub modify_html_refs { Line 11442  sub modify_html_refs {
                 return;                  return;
             }              }
         }           } 
         if (open(my $fh,'<',$container)) {          if (open(my $fh,"<$container")) {
             $content = join('', <$fh>);              $content = join('', <$fh>);
             close($fh);              close($fh);
         } else {          } else {
Line 12495  sub modify_html_refs { Line 11507  sub modify_html_refs {
                         }                          }
                     }                      }
                 } else {                  } else {
                     if (open(my $fh,'>',$container)) {                      if (open(my $fh,">$container")) {
                         print $fh $content;                          print $fh $content;
                         close($fh);                          close($fh);
                         $output = '<p>'.&mt('Updated [quant,_1,reference] in [_2].',                          $output = '<p>'.&mt('Updated [quant,_1,reference] in [_2].',
Line 12533  sub modify_html_refs { Line 11545  sub modify_html_refs {
                         }                          }
                     }                      }
                     if ($rewrites) {                      if ($rewrites) {
                         my $saveresult;                          my $saveresult; 
                         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 13012  sub decompress_uploaded_file { Line 12024  sub decompress_uploaded_file {
   
 sub process_decompression {  sub process_decompression {
     my ($docudom,$docuname,$file,$destination,$dir_root,$hiddenelem) = @_;      my ($docudom,$docuname,$file,$destination,$dir_root,$hiddenelem) = @_;
     unless (($dir_root eq '/userfiles') && ($destination =~ m{^(docs|supplemental)/(default|\d+)/\d+$})) {  
         return '<p class="LC_error">'.&mt('Not extracted.').'<br />'.  
                &mt('Unexpected file path.').'</p>'."\n";  
     }  
     unless (($docudom =~ /^$match_domain$/) && ($docuname =~ /^$match_courseid$/)) {  
         return '<p class="LC_error">'.&mt('Not extracted.').'<br />'.  
                &mt('Unexpected course context.').'</p>'."\n";  
     }  
     unless ($file eq &Apache::lonnet::clean_filename($file)) {  
         return '<p class="LC_error">'.&mt('Not extracted.').'<br />'.  
                &mt('Filename contained unexpected characters.').'</p>'."\n";  
     }  
     my ($dir,$error,$warning,$output);      my ($dir,$error,$warning,$output);
     if ($file !~ /\.(zip|tar|bz2|gz|tar.gz|tar.bz2|tgz)$/i) {      if ($file !~ /\.(zip|tar|bz2|gz|tar.gz|tar.bz2|tgz)$/i) {
         $error = &mt('Filename not a supported archive file type.').          $error = &mt('Filename not a supported archive file type.').
Line 13058  sub process_decompression { Line 12058  sub process_decompression {
                 }                  }
             }              }
             my $numskip = scalar(@to_skip);              my $numskip = scalar(@to_skip);
             my $numoverwrite = scalar(@to_overwrite);              if (($numskip > 0) && 
             if (($numskip) && (!$numoverwrite)) {                  ($numskip == $env{'form.archive_itemcount'})) {
                 $warning = &mt('All items in the archive file already exist, and no overwriting of existing files has been requested.');                           $warning = &mt('All items in the archive file already exist, and no overwriting of existing files has been requested.');         
             } elsif ($dir eq '') {              } elsif ($dir eq '') {
                 $error = &mt('Directory containing archive file unavailable.');                  $error = &mt('Directory containing archive file unavailable.');
             } elsif (!$error) {              } elsif (!$error) {
                 my ($decompressed,$display);                  my ($decompressed,$display);
                 if (($numskip) || ($numoverwrite)) {                  if ($numskip > 0) {
                     my $tempdir = time.'_'.$$.int(rand(10000));                      my $tempdir = time.'_'.$$.int(rand(10000));
                     mkdir("$dir/$tempdir",0755);                      mkdir("$dir/$tempdir",0755);
                     if (&File::Copy::move("$dir/$file","$dir/$tempdir/$file")) {                      system("mv $dir/$file $dir/$tempdir/$file");
                         ($decompressed,$display) =                      ($decompressed,$display) = 
                             &decompress_uploaded_file($file,"$dir/$tempdir");                          &decompress_uploaded_file($file,"$dir/$tempdir");
                         foreach my $item (@to_skip) {                      foreach my $item (@to_skip) {
                             if (($item ne '') && ($item !~ /\.\./)) {                          if (($item ne '') && ($item !~ /\.\./)) {
                                 if (-f "$dir/$tempdir/$item") {                              if (-f "$dir/$tempdir/$item") { 
                                     unlink("$dir/$tempdir/$item");                                  unlink("$dir/$tempdir/$item");
                                 } elsif (-d "$dir/$tempdir/$item") {                              } elsif (-d "$dir/$tempdir/$item") {
                                     &File::Path::remove_tree("$dir/$tempdir/$item",{ safe => 1 });                                  system("rm -rf $dir/$tempdir/$item");
                                 }  
                             }  
                         }  
                         foreach my $item (@to_overwrite) {  
                             if ((-e "$dir/$tempdir/$item") && (-e "$dir/$item")) {  
                                 if (($item ne '') && ($item !~ /\.\./)) {  
                                     if (-f "$dir/$item") {  
                                         unlink("$dir/$item");  
                                     } elsif (-d "$dir/$item") {  
                                         &File::Path::remove_tree("$dir/$item",{ safe => 1 });  
                                     }  
                                     &File::Copy::move("$dir/$tempdir/$item","$dir/$item");  
                                 }  
                             }                              }
                         }                          }
                         if (&File::Copy::move("$dir/$tempdir/$file","$dir/$file")) {  
                             &File::Path::remove_tree("$dir/$tempdir",{ safe => 1 });  
                         }  
                     }                      }
                       system("mv $dir/$tempdir/* $dir");
                       rmdir("$dir/$tempdir");   
                 } else {                  } else {
                     ($decompressed,$display) =                       ($decompressed,$display) = 
                         &decompress_uploaded_file($file,$dir);                          &decompress_uploaded_file($file,$dir);
Line 13113  sub process_decompression { Line 12099  sub process_decompression {
                     if (ref($newdirlistref) eq 'ARRAY') {                      if (ref($newdirlistref) eq 'ARRAY') {
                         foreach my $dir_line (@{$newdirlistref}) {                          foreach my $dir_line (@{$newdirlistref}) {
                             my ($item,undef,undef,$testdir)=split(/\&/,$dir_line,5);                              my ($item,undef,undef,$testdir)=split(/\&/,$dir_line,5);
                             unless (($item =~ /^\.+$/) || ($item eq $file)) {                               unless (($item =~ /^\.+$/) || ($item eq $file) || 
                                       ((@to_skip > 0) && (grep(/^\Q$item\E$/,@to_skip)))) {
                                 push(@newitems,$item);                                  push(@newitems,$item);
                                 if ($dirptr&$testdir) {                                  if ($dirptr&$testdir) {
                                     $is_dir{$item} = 1;                                      $is_dir{$item} = 1;
Line 13168  sub process_decompression { Line 12155  sub process_decompression {
                                     $env{'form.archive_title_'.$i} = $env{'form.camtasia_foldername'};                                      $env{'form.archive_title_'.$i} = $env{'form.camtasia_foldername'};
                                     $displayed{'folder'} = $i;                                      $displayed{'folder'} = $i;
                                 } elsif ((($item eq "$contents[0]/index.html") && ($version == 6)) ||                                  } elsif ((($item eq "$contents[0]/index.html") && ($version == 6)) ||
                                          (($item eq "$contents[0]/$contents[0]".'.html') && ($version == 8))) {                                           (($item eq "$contents[0]/$contents[0]".'.html') && ($version == 8))) { 
                                     $env{'form.archive_'.$i} = 'display';                                      $env{'form.archive_'.$i} = 'display';
                                     $env{'form.archive_title_'.$i} = $env{'form.camtasia_moviename'};                                      $env{'form.archive_title_'.$i} = $env{'form.camtasia_moviename'};
                                     $displayed{'web'} = $i;                                      $displayed{'web'} = $i;
Line 13598  END Line 12585  END
 sub process_extracted_files {  sub process_extracted_files {
     my ($context,$docudom,$docuname,$destination,$dir_root,$hiddenelem) = @_;      my ($context,$docudom,$docuname,$destination,$dir_root,$hiddenelem) = @_;
     my $numitems = $env{'form.archive_count'};      my $numitems = $env{'form.archive_count'};
     return if ((!$numitems) || ($numitems =~ /\D/));      return unless ($numitems);
     my @ids=&Apache::lonnet::current_machine_ids();      my @ids=&Apache::lonnet::current_machine_ids();
     my ($prefix,$pathtocheck,$dir,$ishome,$error,$warning,%toplevelitems,%is_dir,      my ($prefix,$pathtocheck,$dir,$ishome,$error,$warning,%toplevelitems,%is_dir,
         %folders,%containers,%mapinner,%prompttofetch);          %folders,%containers,%mapinner,%prompttofetch);
Line 13611  sub process_extracted_files { Line 12598  sub process_extracted_files {
     } else {      } else {
         $prefix = $Apache::lonnet::perlvar{'lonDocRoot'};          $prefix = $Apache::lonnet::perlvar{'lonDocRoot'};
         $pathtocheck = "$dir_root/$docudom/$docuname/$destination";          $pathtocheck = "$dir_root/$docudom/$docuname/$destination";
         $dir = "$dir_root/$docudom/$docuname";          $dir = "$dir_root/$docudom/$docuname";    
     }      }
     my $currdir = "$dir_root/$destination";      my $currdir = "$dir_root/$destination";
     (my $docstype,$mapinner{'0'}) = ($destination =~ m{^(docs|supplemental)/(\w+)/});      (my $docstype,$mapinner{'0'}) = ($destination =~ m{^(docs|supplemental)/(\w+)/});
Line 13620  sub process_extracted_files { Line 12607  sub process_extracted_files {
         $folders{'0'} = $items[-2];          $folders{'0'} = $items[-2];
         if ($env{'form.folderpath'} =~ /\:1$/) {          if ($env{'form.folderpath'} =~ /\:1$/) {
             $containers{'0'}='page';              $containers{'0'}='page';
         } else {          } else {  
             $containers{'0'}='sequence';              $containers{'0'}='sequence';
         }          }
     }      }
Line 13700  sub process_extracted_files { Line 12687  sub process_extracted_files {
                                                         '.'.$containers{$outer},1,1);                                                          '.'.$containers{$outer},1,1);
                             $newseqid{$i} = $newidx;                              $newseqid{$i} = $newidx;
                             unless ($errtext) {                              unless ($errtext) {
                                 $result .=  '<li>'.&mt('Folder: [_1] added to course',                                  $result .=  '<li>'.&mt('Folder: [_1] added to course',$docstitle).'</li>'."\n";
                                                        &HTML::Entities::encode($docstitle,'<>&"'))..  
                                             '</li>'."\n";  
                             }                              }
                         }                          }
                     } else {                      } else {
Line 13711  sub process_extracted_files { Line 12696  sub process_extracted_files {
                             my $url = '/uploaded/'.$docudom.'/'.$docuname.'/'.                              my $url = '/uploaded/'.$docudom.'/'.$docuname.'/'.
                                       $docstype.'/'.$mapinner{$outer}.'/'.$newidx.'/'.                                        $docstype.'/'.$mapinner{$outer}.'/'.$newidx.'/'.
                                       $title;                                        $title;
                             if (($outer !~ /\D/) &&                              if (!-e "$prefix$dir/$docstype/$mapinner{$outer}") {
                                 (($mapinner{$outer} eq 'default') || ($mapinner{$outer} !~ /\D/)) &&                                  mkdir("$prefix$dir/$docstype/$mapinner{$outer}",0755);
                                 ($newidx !~ /\D/)) {                              }
                                 if (!-e "$prefix$dir/$docstype/$mapinner{$outer}") {                              if (!-e "$prefix$dir/$docstype/$mapinner{$outer}/$newidx") {
                                     mkdir("$prefix$dir/$docstype/$mapinner{$outer}",0755);                                  mkdir("$prefix$dir/$docstype/$mapinner{$outer}/$newidx");
                                 }                              }
                                 if (!-e "$prefix$dir/$docstype/$mapinner{$outer}/$newidx") {                              if (-e "$prefix$dir/$docstype/$mapinner{$outer}/$newidx") {
                                     mkdir("$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";
                                 if (-e "$prefix$dir/$docstype/$mapinner{$outer}/$newidx") {                                  unless ($ishome) {
                                     if (rename("$prefix$path","$prefix$dir/$docstype/$mapinner{$outer}/$newidx/$title")) {                                      my $fetch = "$newdest{$i}/$title";
                                         $newdest{$i} = "$prefix$dir/$docstype/$mapinner{$outer}/$newidx";                                      $fetch =~ s/^\Q$prefix$dir\E//;
                                         unless ($ishome) {                                      $prompttofetch{$fetch} = 1;
                                             my $fetch = "$newdest{$i}/$title";  
                                             $fetch =~ s/^\Q$prefix$dir\E//;  
                                             $prompttofetch{$fetch} = 1;  
                                         }  
                                    }  
                                 }                                  }
                                 $LONCAPA::map::resources[$newidx]=                              }
                                     $docstitle.':'.$url.':false:normal:res';                              $LONCAPA::map::resources[$newidx]=
                                 push(@LONCAPA::map::order, $newidx);                                  $docstitle.':'.$url.':false:normal:res';
                                 my ($outtext,$errtext)=                              push(@LONCAPA::map::order, $newidx);
                                     &LONCAPA::map::storemap('/uploaded/'.$docudom.'/'.                              my ($outtext,$errtext)=
                                                             $docuname.'/'.$folders{$outer}.                                  &LONCAPA::map::storemap('/uploaded/'.$docudom.'/'.
                                                             '.'.$containers{$outer},1,1);                                                          $docuname.'/'.$folders{$outer}.
                                 unless ($errtext) {                                                          '.'.$containers{$outer},1,1);
                                     if (-e "$prefix$dir/$docstype/$mapinner{$outer}/$newidx/$title") {                              unless ($errtext) {
                                         $result .= '<li>'.&mt('File: [_1] added to course',                                  if (-e "$prefix$dir/$docstype/$mapinner{$outer}/$newidx/$title") {
                                                               &HTML::Entities::encode($docstitle,'<>&"')).                                      $result .= '<li>'.&mt('File: [_1] added to course',$docstitle).'</li>'."\n";
                                                    '</li>'."\n";  
                                     }  
                                 }                                  }
                             } else {  
                                 $warning .= &mt('Item extracted from archive: [_1] has unexpected path.',  
                                                 &HTML::Entities::encode($path,'<>&"')).'<br />';  
                             }                              }
                         }                          }
                     }                      }
                 }                  }
             } else {              } else {
                 $warning .= &mt('Item extracted from archive: [_1] has unexpected path.',                  $warning .= &mt('Item extracted from archive: [_1] has unexpected path.',$path).'<br />'; 
                                 &HTML::Entities::encode($path,'<>&"')).'<br />';  
             }              }
         }          }
         for (my $i=1; $i<=$numitems; $i++) {          for (my $i=1; $i<=$numitems; $i++) {
Line 13775  sub process_extracted_files { Line 12749  sub process_extracted_files {
                         }                          }
                         if ($itemidx eq '') {                          if ($itemidx eq '') {
                             $itemidx =  0;                              $itemidx =  0;
                         }                          } 
                         if (grep(/^\Q$referrer{$i}\E$/,@archdirs)) {                          if (grep(/^\Q$referrer{$i}\E$/,@archdirs)) {
                             if ($mapinner{$referrer{$i}}) {                              if ($mapinner{$referrer{$i}}) {
                                 $fullpath = "$prefix$dir/$docstype/$mapinner{$referrer{$i}}";                                  $fullpath = "$prefix$dir/$docstype/$mapinner{$referrer{$i}}";
Line 13814  sub process_extracted_files { Line 12788  sub process_extracted_files {
                         }                          }
                         if ($fullpath ne '') {                          if ($fullpath ne '') {
                             if (-e "$prefix$path") {                              if (-e "$prefix$path") {
                                 unless (rename("$prefix$path","$fullpath/$title")) {                                  system("mv $prefix$path $fullpath/$title");
                                      $warning .= &mt('Failed to rename dependency').'<br />';  
                                 }  
                             }                              }
                             if (-e "$fullpath/$title") {                              if (-e "$fullpath/$title") {
                                 my $showpath;                                  my $showpath;
Line 13824  sub process_extracted_files { Line 12796  sub process_extracted_files {
                                     $showpath = "$relpath/$title";                                      $showpath = "$relpath/$title";
                                 } else {                                  } else {
                                     $showpath = "/$title";                                      $showpath = "/$title";
                                 }                                  } 
                                 $result .= '<li>'.&mt('[_1] included as a dependency',                                  $result .= '<li>'.&mt('[_1] included as a dependency',$showpath).'</li>'."\n";
                                                       &HTML::Entities::encode($showpath,'<>&"')).                              } 
                                            '</li>'."\n";                              unless ($ishome) {
                                 unless ($ishome) {                                  my $fetch = "$fullpath/$title";
                                     my $fetch = "$fullpath/$title";                                  $fetch =~ s/^\Q$prefix$dir\E//; 
                                     $fetch =~ s/^\Q$prefix$dir\E//;                                  $prompttofetch{$fetch} = 1;
                                     $prompttofetch{$fetch} = 1;  
                                 }  
                             }                              }
                         }                          }
                     }                      }
                 } elsif ($env{'form.archive_'.$referrer{$i}} eq 'discard') {                  } elsif ($env{'form.archive_'.$referrer{$i}} eq 'discard') {
                     $warning .= &mt('[_1] is a dependency of [_2], which was discarded.',                      $warning .= &mt('[_1] is a dependency of [_2], which was discarded.',
                                     &HTML::Entities::encode($path,'<>&"'),                                      $path,$env{'form.archive_content_'.$referrer{$i}}).'<br />';
                                     &HTML::Entities::encode($env{'form.archive_content_'.$referrer{$i}},'<>&"')).  
                                 '<br />';  
                 }                  }
             } else {              } else {
                 $warning .= &mt('Item extracted from archive: [_1] has unexpected path.',                  $warning .= &mt('Item extracted from archive: [_1] has unexpected path.',$path).'<br />'; 
                                 &HTML::Entities::encode($path)).'<br />';  
             }              }
         }          }
         if (keys(%todelete)) {          if (keys(%todelete)) {
Line 14118  sub upfile_store { Line 13085  sub upfile_store {
     $env{'form.upfile'}=~s/\n+/\n/gs;      $env{'form.upfile'}=~s/\n+/\n/gs;
     $env{'form.upfile'}=~s/\n+$//gs;      $env{'form.upfile'}=~s/\n+$//gs;
   
     my $datatoken = &valid_datatoken($env{'user.name'}.'_'.$env{'user.domain'}.      my $datatoken=$env{'user.name'}.'_'.$env{'user.domain'}.
                                      '_enroll_'.$env{'request.course.id'}.'_'.   '_enroll_'.$env{'request.course.id'}.'_'.time.'_'.$$;
                                      time.'_'.$$);  
     return if ($datatoken eq '');  
   
     {      {
         my $datafile = $r->dir_config('lonDaemons').          my $datafile = $r->dir_config('lonDaemons').
                            '/tmp/'.$datatoken.'.tmp';                             '/tmp/'.$datatoken.'.tmp';
         if ( open(my $fh,'>',$datafile) ) {          if ( open(my $fh,">$datafile") ) {
             print $fh $env{'form.upfile'};              print $fh $env{'form.upfile'};
             close($fh);              close($fh);
         }          }
Line 14136  sub upfile_store { Line 13100  sub upfile_store {
   
 =pod  =pod
   
 =item * &load_tmp_file($r,$datatoken)  =item * &load_tmp_file($r)
   
 Load uploaded file from tmp, $r should be the HTTP Request object,  Load uploaded file from tmp, $r should be the HTTP Request object,
 $datatoken is the name to assign to the temporary file.  needs $env{'form.datatoken'},
 sets $env{'form.upfile'} to the contents of the file  sets $env{'form.upfile'} to the contents of the file
   
 =cut  =cut
   
 sub load_tmp_file {  sub load_tmp_file {
     my ($r,$datatoken) = @_;      my $r=shift;
     return if ($datatoken eq '');  
     my @studentdata=();      my @studentdata=();
     {      {
         my $studentfile = $r->dir_config('lonDaemons').          my $studentfile = $r->dir_config('lonDaemons').
                               '/tmp/'.$datatoken.'.tmp';                                '/tmp/'.$env{'form.datatoken'}.'.tmp';
         if ( open(my $fh,'<',$studentfile) ) {          if ( open(my $fh,"<$studentfile") ) {
             @studentdata=<$fh>;              @studentdata=<$fh>;
             close($fh);              close($fh);
         }          }
Line 14159  sub load_tmp_file { Line 13122  sub load_tmp_file {
     $env{'form.upfile'}=join('',@studentdata);      $env{'form.upfile'}=join('',@studentdata);
 }  }
   
 sub valid_datatoken {  
     my ($datatoken) = @_;  
     if ($datatoken =~ /^$match_username\_$match_domain\_enroll_(|$match_domain\_$match_courseid)\_\d+_\d+$/) {  
         return $datatoken;  
     }  
     return;  
 }  
   
 =pod  =pod
   
 =item * &upfile_record_sep()  =item * &upfile_record_sep()
Line 14607  sub DrawBarGraph { Line 13562  sub DrawBarGraph {
         @Labels = @$labels;          @Labels = @$labels;
     } else {      } else {
         for (my $i=0;$i<@{$Values[0]};$i++) {          for (my $i=0;$i<@{$Values[0]};$i++) {
             push(@Labels,$i+1);              push (@Labels,$i+1);
         }          }
     }      }
     #      #
Line 15046  generated by lonerrorhandler.pm, CHECKRP Line 14001  generated by lonerrorhandler.pm, CHECKRP
 lonsupportreq.pm, loncoursequeueadmin.pm, searchcat.pl respectively.  lonsupportreq.pm, loncoursequeueadmin.pm, searchcat.pl respectively.
   
 Inputs:  Inputs:
 defmail (scalar - email address of default recipient),  defmail (scalar - email address of default recipient), 
 mailing type (scalar: errormail, packagesmail, helpdeskmail,  mailing type (scalar: errormail, packagesmail, helpdeskmail,
 requestsmail, updatesmail, or idconflictsmail).  requestsmail, updatesmail, or idconflictsmail).
   
 defdom (domain for which to retrieve configuration settings),  defdom (domain for which to retrieve configuration settings),
   
 origmail (scalar - email address of recipient from loncapa.conf,  origmail (scalar - email address of recipient from loncapa.conf, 
 i.e., predates configuration by DC via domainprefs.pm  i.e., predates configuration by DC via domainprefs.pm 
   
 $requname username of requester (if mailing type is helpdeskmail)  
   
 $requdom domain of requester (if mailing type is helpdeskmail)  
   
 $reqemail e-mail address of requester (if mailing type is helpdeskmail)  
   
 Returns: comma separated list of addresses to which to send e-mail.  Returns: comma separated list of addresses to which to send e-mail.
   
Line 15070  Returns: comma separated list of address Line 14019  Returns: comma separated list of address
 ############################################################  ############################################################
 ############################################################  ############################################################
 sub build_recipient_list {  sub build_recipient_list {
     my ($defmail,$mailing,$defdom,$origmail,$requname,$requdom,$reqemail) = @_;      my ($defmail,$mailing,$defdom,$origmail) = @_;
     my @recipients;      my @recipients;
     my ($otheremails,$lastresort,$allbcc,$addtext);      my $otheremails;
     my %domconfig =      my %domconfig =
         &Apache::lonnet::get_dom('configuration',['contacts'],$defdom);           &Apache::lonnet::get_dom('configuration',['contacts'],$defdom);
     if (ref($domconfig{'contacts'}) eq 'HASH') {      if (ref($domconfig{'contacts'}) eq 'HASH') {
         if (exists($domconfig{'contacts'}{$mailing})) {          if (exists($domconfig{'contacts'}{$mailing})) {
             if (ref($domconfig{'contacts'}{$mailing}) eq 'HASH') {              if (ref($domconfig{'contacts'}{$mailing}) eq 'HASH') {
Line 15086  sub build_recipient_list { Line 14035  sub build_recipient_list {
                             push(@recipients,$addr);                              push(@recipients,$addr);
                         }                          }
                     }                      }
                 }                      $otheremails = $domconfig{'contacts'}{$mailing}{'others'};
                 $otheremails = $domconfig{'contacts'}{$mailing}{'others'};  
                 if ($mailing eq 'helpdeskmail') {  
                     if ($domconfig{'contacts'}{$mailing}{'bcc'}) {  
                         my @bccs = split(/,/,$domconfig{'contacts'}{$mailing}{'bcc'});  
                         my @ok_bccs;  
                         foreach my $bcc (@bccs) {  
                             $bcc =~ s/^\s+//g;  
                             $bcc =~ s/\s+$//g;  
                             if ($bcc =~ m/^[^\@]+\@[^\@]+$/) {  
                                 if (!(grep(/^\Q$bcc\E$/,@ok_bccs))) {  
                                     push(@ok_bccs,$bcc);  
                                 }  
                             }  
                         }  
                         if (@ok_bccs > 0) {  
                             $allbcc = join(', ',@ok_bccs);  
                         }  
                     }  
                     $addtext = $domconfig{'contacts'}{$mailing}{'include'};  
                 }                  }
             }              }
         } elsif ($origmail ne '') {          } elsif ($origmail ne '') {
             $lastresort = $origmail;              push(@recipients,$origmail);
         }  
         if ($mailing eq 'helpdeskmail') {  
             if ((ref($domconfig{'contacts'}{'overrides'}) eq 'HASH') &&  
                 (keys(%{$domconfig{'contacts'}{'overrides'}}))) {  
                 my ($inststatus,$inststatus_checked);  
                 if (($env{'user.name'} ne '') && ($env{'user.domain'} ne '') &&  
                     ($env{'user.domain'} ne 'public')) {  
                     $inststatus_checked = 1;  
                     $inststatus = $env{'environment.inststatus'};  
                 }  
                 unless ($inststatus_checked) {  
                     if (($requname ne '') && ($requdom ne '')) {  
                         if (($requname =~ /^$match_username$/) &&  
                             ($requdom =~ /^$match_domain$/) &&  
                             (&Apache::lonnet::domain($requdom))) {  
                             my $requhome = &Apache::lonnet::homeserver($requname,  
                                                                       $requdom);  
                             unless ($requhome eq 'no_host') {  
                                 my %userenv = &Apache::lonnet::userenvironment($requdom,$requname,'inststatus');  
                                 $inststatus = $userenv{'inststatus'};  
                                 $inststatus_checked = 1;  
                             }  
                         }  
                     }  
                 }  
                 unless ($inststatus_checked) {  
                     if ($reqemail =~ /^[^\@]+\@[^\@]+$/) {  
                         my %srch = (srchby     => 'email',  
                                     srchdomain => $defdom,  
                                     srchterm   => $reqemail,  
                                     srchtype   => 'exact');  
                         my %srch_results = &Apache::lonnet::usersearch(\%srch);  
                         foreach my $uname (keys(%srch_results)) {  
                             if (ref($srch_results{$uname}{'inststatus'}) eq 'ARRAY') {  
                                 $inststatus = join(',',@{$srch_results{$uname}{'inststatus'}});  
                                 $inststatus_checked = 1;  
                                 last;  
                             }  
                         }  
                         unless ($inststatus_checked) {  
                             my ($dirsrchres,%srch_results) = &Apache::lonnet::inst_directory_query(\%srch);  
                             if ($dirsrchres eq 'ok') {  
                                 foreach my $uname (keys(%srch_results)) {  
                                     if (ref($srch_results{$uname}{'inststatus'}) eq 'ARRAY') {  
                                         $inststatus = join(',',@{$srch_results{$uname}{'inststatus'}});  
                                         $inststatus_checked = 1;  
                                         last;  
                                     }  
                                 }  
                             }  
                         }  
                     }  
                 }  
                 if ($inststatus ne '') {  
                     foreach my $status (split(/\:/,$inststatus)) {  
                         if (ref($domconfig{'contacts'}{'overrides'}{$status}) eq 'HASH') {  
                             my @contacts = ('adminemail','supportemail');  
                             foreach my $item (@contacts) {  
                                 if ($domconfig{'contacts'}{'overrides'}{$status}{$item}) {  
                                     my $addr = $domconfig{'contacts'}{'overrides'}{$status};  
                                     if (!grep(/^\Q$addr\E$/,@recipients)) {  
                                         push(@recipients,$addr);  
                                     }  
                                 }  
                             }  
                             $otheremails = $domconfig{'contacts'}{'overrides'}{$status}{'others'};  
                             if ($domconfig{'contacts'}{'overrides'}{$status}{'bcc'}) {  
                                 my @bccs = split(/,/,$domconfig{'contacts'}{'overrides'}{$status}{'bcc'});  
                                 my @ok_bccs;  
                                 foreach my $bcc (@bccs) {  
                                     $bcc =~ s/^\s+//g;  
                                     $bcc =~ s/\s+$//g;  
                                     if ($bcc =~ m/^[^\@]+\@[^\@]+$/) {  
                                         if (!(grep(/^\Q$bcc\E$/,@ok_bccs))) {  
                                             push(@ok_bccs,$bcc);  
                                         }  
                                     }  
                                 }  
                                 if (@ok_bccs > 0) {  
                                     $allbcc = join(', ',@ok_bccs);  
                                 }  
                             }  
                             $addtext = $domconfig{'contacts'}{'overrides'}{$status}{'include'};  
                             last;  
                         }  
                     }  
                 }  
             }  
         }          }
     } elsif ($origmail ne '') {      } elsif ($origmail ne '') {
         $lastresort = $origmail;          push(@recipients,$origmail);
     }  
     if (($mailing eq 'helpdeskmail') && ($lastresort ne '')) {  
         unless (grep(/^\Q$defdom\E$/,&Apache::lonnet::current_machine_domains())) {  
             my $lonhost = $Apache::lonnet::perlvar{'lonHostID'};  
             my $machinedom = $Apache::lonnet::perlvar{'lonDefDomain'};  
             my %what = (  
                           perlvar => 1,  
                        );  
             my $primary = &Apache::lonnet::domain($defdom,'primary');  
             if ($primary) {  
                 my $gotaddr;  
                 my ($result,$returnhash) =  
                     &Apache::lonnet::get_remote_globals($primary,{ perlvar => 1 });  
                 if (($result eq 'ok') && (ref($returnhash) eq 'HASH')) {  
                     if ($returnhash->{'lonSupportEMail'} =~ /^[^\@]+\@[^\@]+$/) {  
                         $lastresort = $returnhash->{'lonSupportEMail'};  
                         $gotaddr = 1;  
                     }  
                 }  
                 unless ($gotaddr) {  
                     my $uintdom = &Apache::lonnet::internet_dom($primary);  
                     my $intdom = &Apache::lonnet::internet_dom($lonhost);  
                     unless ($uintdom eq $intdom) {  
                         my %domconfig =  
                             &Apache::lonnet::get_dom('configuration',['contacts'],$machinedom);  
                         if (ref($domconfig{'contacts'}) eq 'HASH') {  
                             if (ref($domconfig{'contacts'}{'otherdomsmail'}) eq 'HASH') {  
                                 my @contacts = ('adminemail','supportemail');  
                                 foreach my $item (@contacts) {  
                                     if ($domconfig{'contacts'}{'otherdomsmail'}{$item}) {  
                                         my $addr = $domconfig{'contacts'}{$item};  
                                         if (!grep(/^\Q$addr\E$/,@recipients)) {  
                                             push(@recipients,$addr);  
                                         }  
                                     }  
                                 }  
                                 if ($domconfig{'contacts'}{'otherdomsmail'}{'others'}) {  
                                     $otheremails = $domconfig{'contacts'}{'otherdomsmail'}{'others'};  
                                 }  
                                 if ($domconfig{'contacts'}{'otherdomsmail'}{'bcc'}) {  
                                     my @bccs = split(/,/,$domconfig{'contacts'}{'otherdomsmail'}{'bcc'});  
                                     my @ok_bccs;  
                                     foreach my $bcc (@bccs) {  
                                         $bcc =~ s/^\s+//g;  
                                         $bcc =~ s/\s+$//g;  
                                         if ($bcc =~ m/^[^\@]+\@[^\@]+$/) {  
                                             if (!(grep(/^\Q$bcc\E$/,@ok_bccs))) {  
                                                 push(@ok_bccs,$bcc);  
                                             }  
                                         }  
                                     }  
                                     if (@ok_bccs > 0) {  
                                         $allbcc = join(', ',@ok_bccs);  
                                     }  
                                 }  
                                 $addtext = $domconfig{'contacts'}{'otherdomsmail'}{'include'};  
                             }  
                         }  
                     }  
                 }  
             }  
         }  
     }      }
     if (defined($defmail)) {      if (defined($defmail)) {
         if ($defmail ne '') {          if ($defmail ne '') {
Line 15282  sub build_recipient_list { Line 14062  sub build_recipient_list {
             }              }
         }          }
     }      }
     if ($mailing eq 'helpdeskmail') {      my $recipientlist = join(',',@recipients); 
         if ((!@recipients) && ($lastresort ne '')) {      return $recipientlist;
             push(@recipients,$lastresort);  }
         }  
     } elsif ($lastresort ne '') {  ############################################################
         if (!grep(/^\Q$lastresort\E$/,@recipients)) {  ############################################################
             push(@recipients,$lastresort);  
         }  =pod
   
   =over 4
   
   =item * &mime_email()
   
   Sends an email with a possible attachment
   
   Inputs:
   
   =over 4
   
   from -              Sender's email address
   
   to -                Email address of recipient
   
   subject -           Subject of email
   
   body -              Body of email
   
   cc_string -         Carbon copy email address
   
   bcc -               Blind carbon copy email address
   
   type -              File type of attachment
   
   attachment_path -   Path of file to be attached
   
   file_name -         Name of file to be attached
   
   attachment_text -   The body of an attachment of type "TEXT"
   
   =back
   
   =back
   
   =cut
   
   ############################################################
   ############################################################
   
   sub mime_email {
       my ($from, $to, $subject, $body, $cc_string, $bcc, $attachment_path, 
           $file_name, $attachment_text) = @_;
       my $msg = MIME::Lite->new(
                From    => $from,
                To      => $to,
                Subject => $subject,
                Type    =>'TEXT',
                Data    => $body,
                );
       if ($cc_string ne '') {
           $msg->add("Cc" => $cc_string);
     }      }
     my $recipientlist = join(',',@recipients);      if ($bcc ne '') {
     if (wantarray) {          $msg->add("Bcc" => $bcc);
         return ($recipientlist,$allbcc,$addtext);  
     } else {  
         return $recipientlist;  
     }      }
       $msg->attr("content-type"         => "text/plain");
       $msg->attr("content-type.charset" => "UTF-8");
       # Attach file if given
       if ($attachment_path) {
           unless ($file_name) {
               if ($attachment_path =~ m-/([^/]+)$-) { $file_name = $1; }
           }
           my ($type, $encoding) = MIME::Types::by_suffix($attachment_path);
           $msg->attach(Type     => $type,
                        Path     => $attachment_path,
                        Filename => $file_name
                        );
       # Otherwise attach text if given
       } elsif ($attachment_text) {
           $msg->attach(Type => 'TEXT',
                        Data => $attachment_text);
       }
       # Send it
       $msg->send('sendmail');
 }  }
   
 ############################################################  ############################################################
Line 15387  jsarray (reference to array of categorie Line 14235  jsarray (reference to array of categorie
 subcats (reference to hash of arrays containing all subcategories within each   subcats (reference to hash of arrays containing all subcategories within each 
          category, -recursive)           category, -recursive)
   
 maxd (reference to hash used to hold max depth for all top-level categories).  
   
 Returns: nothing  Returns: nothing
   
 Side effects: populates trails and allitems hash references.  Side effects: populates trails and allitems hash references.
Line 15396  Side effects: populates trails and allit Line 14242  Side effects: populates trails and allit
 =cut  =cut
   
 sub extract_categories {  sub extract_categories {
     my ($categories,$cats,$trails,$allitems,$idx,$jsarray,$subcats,$maxd) = @_;      my ($categories,$cats,$trails,$allitems,$idx,$jsarray,$subcats) = @_;
     if (ref($categories) eq 'HASH') {      if (ref($categories) eq 'HASH') {
         &gather_categories($categories,$cats,$idx,$jsarray);          &gather_categories($categories,$cats,$idx,$jsarray);
         if (ref($cats->[0]) eq 'ARRAY') {          if (ref($cats->[0]) eq 'ARRAY') {
Line 15422  sub extract_categories { Line 14268  sub extract_categories {
                         if (ref($subcats) eq 'HASH') {                          if (ref($subcats) eq 'HASH') {
                             push(@{$subcats->{$item}},&escape($category).':'.&escape($name).':1');                              push(@{$subcats->{$item}},&escape($category).':'.&escape($name).':1');
                         }                          }
                         &recurse_categories($cats,2,$category,$trails,$allitems,\@parents,$subcats,$maxd);                          &recurse_categories($cats,2,$category,$trails,$allitems,\@parents,$subcats);
                     }                      }
                 } else {                  } else {
                     if (ref($subcats) eq 'HASH') {                      if (ref($subcats) eq 'HASH') {
                         $subcats->{$item} = [];                          $subcats->{$item} = [];
                     }                      }
                     if (ref($maxd) eq 'HASH') {  
                         $maxd->{$name} = 1;  
                     }  
                 }                  }
             }              }
         }          }
Line 15468  Side effects: populates trails and allit Line 14311  Side effects: populates trails and allit
 =cut  =cut
   
 sub recurse_categories {  sub recurse_categories {
     my ($cats,$depth,$category,$trails,$allitems,$parents,$subcats,$maxd) = @_;      my ($cats,$depth,$category,$trails,$allitems,$parents,$subcats) = @_;
     my $shallower = $depth - 1;      my $shallower = $depth - 1;
     if (ref($cats->[$depth]{$category}) eq 'ARRAY') {      if (ref($cats->[$depth]{$category}) eq 'ARRAY') {
         for (my $k=0; $k<@{$cats->[$depth]{$category}}; $k++) {          for (my $k=0; $k<@{$cats->[$depth]{$category}}; $k++) {
             my $name = $cats->[$depth]{$category}[$k];              my $name = $cats->[$depth]{$category}[$k];
             my $item = &escape($category).':'.&escape($parents->[-1]).':'.$shallower;              my $item = &escape($category).':'.&escape($parents->[-1]).':'.$shallower;
             my $trailstr = join(' &raquo; ',(@{$parents},$category));              my $trailstr = join(' -&gt; ',(@{$parents},$category));
             if ($allitems->{$item} eq '') {              if ($allitems->{$item} eq '') {
                 push(@{$trails},$trailstr);                  push(@{$trails},$trailstr);
                 $allitems->{$item} = scalar(@{$trails})-1;                  $allitems->{$item} = scalar(@{$trails})-1;
Line 15495  sub recurse_categories { Line 14338  sub recurse_categories {
                 }                  }
             }              }
             &recurse_categories($cats,$deeper,$name,$trails,$allitems,$parents,              &recurse_categories($cats,$deeper,$name,$trails,$allitems,$parents,
                                 $subcats,$maxd);                                  $subcats);
             pop(@{$parents});              pop(@{$parents});
         }          }
     } else {      } else {
         my $item = &escape($category).':'.&escape($parents->[-1]).':'.$shallower;          my $item = &escape($category).':'.&escape($parents->[-1]).':'.$shallower;
         my $trailstr = join(' &raquo; ',(@{$parents},$category));          my $trailstr = join(' -&gt; ',(@{$parents},$category));
         if ($allitems->{$item} eq '') {          if ($allitems->{$item} eq '') {
             push(@{$trails},$trailstr);              push(@{$trails},$trailstr);
             $allitems->{$item} = scalar(@{$trails})-1;              $allitems->{$item} = scalar(@{$trails})-1;
         }          }
         if (ref($maxd) eq 'HASH') {  
             if ($depth > $maxd->{$parents->[0]}) {  
                 $maxd->{$parents->[0]} = $depth;  
             }  
         }  
     }      }
     return;      return;
 }  }
Line 15530  currcat - scalar with an & separated lis Line 14368  currcat - scalar with an & separated lis
   
 type    - scalar contains course type (Course or Community).  type    - scalar contains course type (Course or Community).
   
 disabled - scalar (optional) contains disabled="disabled" if input elements are  
            to be readonly (e.g., Domain Helpdesk role viewing course settings).  
   
 Returns: $output (markup to be displayed)   Returns: $output (markup to be displayed) 
   
 =cut  =cut
   
 sub assign_categories_table {  sub assign_categories_table {
     my ($cathash,$currcat,$type,$disabled) = @_;      my ($cathash,$currcat,$type) = @_;
     my $output;      my $output;
     if (ref($cathash) eq 'HASH') {      if (ref($cathash) eq 'HASH') {
         my (@cats,@trails,%allitems,%idx,@jsarray,%maxd,@path,$maxdepth);          my (@cats,@trails,%allitems,%idx,@jsarray,@path,$maxdepth);
         &extract_categories($cathash,\@cats,\@trails,\%allitems,\%idx,\@jsarray,\%maxd);          &extract_categories($cathash,\@cats,\@trails,\%allitems,\%idx,\@jsarray);
         $maxdepth = scalar(@cats);          $maxdepth = scalar(@cats);
         if (@cats > 0) {          if (@cats > 0) {
             my $itemcount = 0;              my $itemcount = 0;
Line 15574  sub assign_categories_table { Line 14409  sub assign_categories_table {
                     }                      }
                     $table .= '<tr '.$css_class.'><td><span class="LC_nobreak">'.                      $table .= '<tr '.$css_class.'><td><span class="LC_nobreak">'.
                               '<input type="checkbox" name="usecategory" value="'.                                '<input type="checkbox" name="usecategory" value="'.
                               $item.'"'.$checked.$disabled.' />'.$parent_title.'</span>'.                                $item.'"'.$checked.' />'.$parent_title.'</span>'.
                               '<input type="hidden" name="catname" value="'.$parent.'" /></td>';                                '<input type="hidden" name="catname" value="'.$parent.'" /></td>';
                     my $depth = 1;                      my $depth = 1;
                     push(@path,$parent);                      push(@path,$parent);
                     $table .= &assign_category_rows($itemcount,\@cats,$depth,$parent,\@path,\@currcategories,$disabled);                      $table .= &assign_category_rows($itemcount,\@cats,$depth,$parent,\@path,\@currcategories);
                     pop(@path);                      pop(@path);
                     $table .= '</tr><tr><td colspan="'.$maxdepth.'" class="LC_row_separator"></td></tr>';                      $table .= '</tr><tr><td colspan="'.$maxdepth.'" class="LC_row_separator"></td></tr>';
                     $itemcount ++;                      $itemcount ++;
Line 15617  path - Array containing all categories b Line 14452  path - Array containing all categories b
   
 currcategories - reference to array of current categories assigned to the course  currcategories - reference to array of current categories assigned to the course
   
 disabled - scalar (optional) contains disabled="disabled" if input elements are  
            to be readonly (e.g., Domain Helpdesk role viewing course settings).  
   
 Returns: $output (markup to be displayed).  Returns: $output (markup to be displayed).
   
 =cut  =cut
   
 sub assign_category_rows {  sub assign_category_rows {
     my ($itemcount,$cats,$depth,$parent,$path,$currcategories,$disabled) = @_;      my ($itemcount,$cats,$depth,$parent,$path,$currcategories) = @_;
     my ($text,$name,$item,$chgstr);      my ($text,$name,$item,$chgstr);
     if (ref($cats) eq 'ARRAY') {      if (ref($cats) eq 'ARRAY') {
         my $maxdepth = scalar(@{$cats});          my $maxdepth = scalar(@{$cats});
Line 15648  sub assign_category_rows { Line 14480  sub assign_category_rows {
                     }                      }
                     $text .= '<tr><td><span class="LC_nobreak"><label>'.                      $text .= '<tr><td><span class="LC_nobreak"><label>'.
                              '<input type="checkbox" name="usecategory" value="'.                               '<input type="checkbox" name="usecategory" value="'.
                              $item.'"'.$checked.$disabled.' />'.$name.'</label></span>'.                               $item.'"'.$checked.' />'.$name.'</label></span>'.
                              '<input type="hidden" name="catname" value="'.$name.'" />'.                               '<input type="hidden" name="catname" value="'.$name.'" />'.
                              '</td><td>';                               '</td><td>';
                     if (ref($path) eq 'ARRAY') {                      if (ref($path) eq 'ARRAY') {
                         push(@{$path},$name);                          push(@{$path},$name);
                         $text .= &assign_category_rows($itemcount,$cats,$deeper,$name,$path,$currcategories,$disabled);                          $text .= &assign_category_rows($itemcount,$cats,$deeper,$name,$path,$currcategories);
                         pop(@{$path});                          pop(@{$path});
                     }                      }
                     $text .= '</td></tr>';                      $text .= '</td></tr>';
Line 15752  sub commit_studentrole { Line 14584  sub commit_studentrole {
                 }                  }
                 $oldsecurl = $uurl;                  $oldsecurl = $uurl;
                 $expire_role_result =                   $expire_role_result = 
                     &Apache::lonnet::assignrole($udom,$uname,$uurl,'st',$now,'','','',$context);                      &Apache::lonnet::assignrole($udom,$uname,$uurl,'st',$now,'','',$context);
                 if ($env{'request.course.sec'} ne '') {                   if ($env{'request.course.sec'} ne '') { 
                     if ($expire_role_result eq 'refused') {                      if ($expire_role_result eq 'refused') {
                         my @roles = ('st');                          my @roles = ('st');
Line 15801  sub commit_studentrole { Line 14633  sub commit_studentrole {
                     }                      }
                 }                  }
             } else {              } else {
                 if ($secchange) {                         if ($secchange) { 
                     $$logmsg .= &mt('Error when attempting section change for [_1] from old section "[_2]" to new section: "[_3]" in course [_4] -error:',$uname,$oldsec,$sec,$cid).' '.$modify_section_result.$linefeed;                      $$logmsg .= &mt('Error when attempting section change for [_1] from old section "[_2]" to new section: "[_3]" in course [_4] -error:',$uname,$oldsec,$sec,$cid).' '.$modify_section_result.$linefeed;
                 } else {                  } else {
                     $$logmsg .= &mt('Error when attempting to modify role for [_1] for section: "[_2]" in course [_3] -error:',$uname,$sec,$cid).' '.$modify_section_result.$linefeed;                      $$logmsg .= &mt('Error when attempting to modify role for [_1] for section: "[_2]" in course [_3] -error:',$uname,$sec,$cid).' '.$modify_section_result.$linefeed;
Line 15864  sub check_clone { Line 14696  sub check_clone {
     my $cloneid='/'.$args->{'clonedomain'}.'/'.$args->{'clonecourse'};      my $cloneid='/'.$args->{'clonedomain'}.'/'.$args->{'clonecourse'};
     my ($clonecrsudom,$clonecrsunum)= &LONCAPA::split_courseid($cloneid);      my ($clonecrsudom,$clonecrsunum)= &LONCAPA::split_courseid($cloneid);
     my $clonehome=&Apache::lonnet::homeserver($clonecrsunum,$clonecrsudom);      my $clonehome=&Apache::lonnet::homeserver($clonecrsunum,$clonecrsudom);
     my $clonetitle;      my $clonemsg;
     my @clonemsg;  
     my $can_clone = 0;      my $can_clone = 0;
     my $lctype = lc($args->{'crstype'});      my $lctype = lc($args->{'crstype'});
     if ($lctype ne 'community') {      if ($lctype ne 'community') {
Line 15873  sub check_clone { Line 14704  sub check_clone {
     }      }
     if ($clonehome eq 'no_host') {      if ($clonehome eq 'no_host') {
         if ($args->{'crstype'} eq 'Community') {          if ($args->{'crstype'} eq 'Community') {
             push(@clonemsg,({              $clonemsg = &mt('No new community created.').$linefeed.&mt('A new community could not be cloned from the specified original - [_1] - because it is a non-existent community.',$args->{'clonecourse'}.':'.$args->{'clonedomain'});
                               mt => 'No new community created.',  
                               args => [],  
                             },  
                             {  
                               mt => 'A new community could not be cloned from the specified original - [_1] - because it is a non-existent community.',  
                               args => [$args->{'clonedomain'}.':'.$args->{'clonedomain'}],  
                             }));  
         } else {          } else {
             push(@clonemsg,({              $clonemsg = &mt('No new course created.').$linefeed.&mt('A new course could not be cloned from the specified original - [_1] - because it is a non-existent course.',$args->{'clonecourse'}.':'.$args->{'clonedomain'});
                               mt => 'No new course created.',          }     
                               args => [],  
                             },  
                             {  
                               mt => 'A new course could not be cloned from the specified original - [_1] - because it is a non-existent course.',  
                               args => [$args->{'clonecourse'}.':'.$args->{'clonedomain'}],  
                             }));  
         }  
     } else {      } else {
  my %clonedesc = &Apache::lonnet::coursedescription($cloneid,{'one_time' => 1});   my %clonedesc = &Apache::lonnet::coursedescription($cloneid,{'one_time' => 1});
         $clonetitle = $clonedesc{'description'};  
         if ($args->{'crstype'} eq 'Community') {          if ($args->{'crstype'} eq 'Community') {
             if ($clonedesc{'type'} ne 'Community') {              if ($clonedesc{'type'} ne 'Community') {
                 push(@clonemsg,({                   $clonemsg = &mt('No new community created.').$linefeed.&mt('A new community could not be cloned from the specified original - [_1] - because it is a course not a community.',$args->{'clonecourse'}.':'.$args->{'clonedomain'});
                                   mt => 'No new community created.',                  return ($can_clone, $clonemsg, $cloneid, $clonehome);
                                   args => [],  
                                 },  
                                 {  
                                   mt => 'A new community could not be cloned from the specified original - [_1] - because it is a course not a community.',  
                                   args => [$args->{'clonecourse'}.':'.$args->{'clonedomain'}],  
                                 }));  
                 return ($can_clone,\@clonemsg,$cloneid,$clonehome);  
             }              }
         }          }
  if (($env{'request.role.domain'} eq $args->{'clonedomain'}) &&   if (($env{'request.role.domain'} eq $args->{'clonedomain'}) && 
             (&Apache::lonnet::allowed('ccc',$env{'request.role.domain'}))) {              (&Apache::lonnet::allowed('ccc',$env{'request.role.domain'}))) {
     $can_clone = 1;      $can_clone = 1;
  } else {   } else {
Line 15921  sub check_clone { Line 14730  sub check_clone {
                             if ($args->{'ccdomain'} eq $args->{'clonedomain'}) {                              if ($args->{'ccdomain'} eq $args->{'clonedomain'}) {
                                 $can_clone = 1;                                  $can_clone = 1;
                             }                              }
                         } elsif (($clonehash{'internal.coursecode'}) && ($args->{'crscode'}) &&                          } elsif (($clonehash{'internal.coursecode'}) && ($args->{'crscode'}) && 
                                  ($args->{'clonedomain'} eq  $args->{'course_domain'})) {                                   ($args->{'clonedomain'} eq  $args->{'course_domain'})) {
                             if (&Apache::lonnet::default_instcode_cloning($args->{'clonedomain'},$domdefs{'canclone'},                              if (&Apache::lonnet::default_instcode_cloning($args->{'clonedomain'},$domdefs{'canclone'},
                                                                           $clonehash{'internal.coursecode'},$args->{'crscode'})) {                                                                            $clonehash{'internal.coursecode'},$args->{'crscode'})) {
Line 15940  sub check_clone { Line 14749  sub check_clone {
                     $can_clone = 1;                      $can_clone = 1;
                 }                  }
                 unless ($can_clone) {                  unless ($can_clone) {
                     if (($clonehash{'internal.coursecode'}) && ($args->{'crscode'}) &&                      if (($clonehash{'internal.coursecode'}) && ($args->{'crscode'}) && 
                         ($args->{'clonedomain'} eq  $args->{'course_domain'})) {                          ($args->{'clonedomain'} eq  $args->{'course_domain'})) {
                         my (%gotdomdefaults,%gotcodedefaults);                          my (%gotdomdefaults,%gotcodedefaults);
                         foreach my $cloner (@cloners) {                          foreach my $cloner (@cloners) {
Line 15979  sub check_clone { Line 14788  sub check_clone {
                 if ($args->{'crstype'} eq 'Community') {                  if ($args->{'crstype'} eq 'Community') {
                     $ccrole = 'co';                      $ccrole = 'co';
                 }                  }
                 my %roleshash =          my %roleshash =
                     &Apache::lonnet::get_my_roles($args->{'ccuname'},      &Apache::lonnet::get_my_roles($args->{'ccuname'},
                                                   $args->{'ccdomain'},            $args->{'ccdomain'},
                                                   'userroles',['active'],[$ccrole],                                                    'userroles',['active'],[$ccrole],
                                                   [$args->{'clonedomain'}]);            [$args->{'clonedomain'}]);
                 if ($roleshash{$args->{'clonecourse'}.':'.$args->{'clonedomain'}.':'.$ccrole}) {          if ($roleshash{$args->{'clonecourse'}.':'.$args->{'clonedomain'}.':'.$ccrole}) {
                     $can_clone = 1;                      $can_clone = 1;
                 } elsif (&Apache::lonnet::is_course_owner($args->{'clonedomain'},$args->{'clonecourse'},                  } elsif (&Apache::lonnet::is_course_owner($args->{'clonedomain'},$args->{'clonecourse'},
                                                           $args->{'ccuname'},$args->{'ccdomain'})) {                                                            $args->{'ccuname'},$args->{'ccdomain'})) {
Line 15993  sub check_clone { Line 14802  sub check_clone {
             }              }
             unless ($can_clone) {              unless ($can_clone) {
                 if ($args->{'crstype'} eq 'Community') {                  if ($args->{'crstype'} eq 'Community') {
                     push(@clonemsg,({                      $clonemsg = &mt('No new community created.').$linefeed.&mt('The new community could not be cloned from the existing community because the new community owner ([_1]) does not have cloning rights in the existing community ([_2]).',$args->{'ccuname'}.':'.$args->{'ccdomain'},$clonedesc{'description'});
                                       mt => 'No new community created.',  
                                       args => [],  
                                     },  
                                     {  
                                       mt => 'The new community could not be cloned from the existing community because the new community owner ([_1]) does not have cloning rights in the existing community ([_2]).',  
                                       args => [$args->{'ccuname'}.':'.$args->{'ccdomain'},$clonedesc{'description'}],  
                                     }));  
                 } else {                  } else {
                     push(@clonemsg,({                      $clonemsg = &mt('No new course created.').$linefeed.&mt('The new course could not be cloned from the existing course because the new course owner ([_1]) does not have cloning rights in the existing course ([_2]).',$args->{'ccuname'}.':'.$args->{'ccdomain'},$clonedesc{'description'});
                                       mt => 'No new course created.',                  }
                                       args => [],  
                                     },  
                                     {  
                                       mt => 'The new course could not be cloned from the existing course because the new course owner ([_1]) does not have cloning rights in the existing course ([_2]).',  
                                       args => [$args->{'ccuname'}.':'.$args->{'ccdomain'},$clonedesc{'description'}],  
                                     }));  
         }  
     }      }
         }          }
     }      }
     return ($can_clone,\@clonemsg,$cloneid,$clonehome,$clonetitle);      return ($can_clone, $clonemsg, $cloneid, $clonehome);
 }  }
   
 sub construct_course {  sub construct_course {
     my ($args,$logmsg,$courseid,$crsudom,$crsunum,$udom,$uname,$context,      my ($args,$logmsg,$courseid,$crsudom,$crsunum,$udom,$uname,$context,$cnum,$category,$coderef) = @_;
         $cnum,$category,$coderef,$callercontext,$user_lh) = @_;      my $outcome;
     my ($outcome,$msgref,$clonemsgref);  
     my $linefeed =  '<br />'."\n";      my $linefeed =  '<br />'."\n";
     if ($context eq 'auto') {      if ($context eq 'auto') {
         $linefeed = "\n";          $linefeed = "\n";
Line 16029  sub construct_course { Line 14823  sub construct_course {
 #  #
 # Are we cloning?  # Are we cloning?
 #  #
     my ($can_clone,$cloneid,$clonehome,$clonetitle);      my ($can_clone, $clonemsg, $cloneid, $clonehome);
     if (($args->{'clonecourse'}) && ($args->{'clonedomain'})) {      if (($args->{'clonecourse'}) && ($args->{'clonedomain'})) {
  ($can_clone,$clonemsgref,$cloneid,$clonehome,$clonetitle) = &check_clone($args,$linefeed);   ($can_clone, $clonemsg, $cloneid, $clonehome) = &check_clone($args,$linefeed);
    if ($context ne 'auto') {
               if ($clonemsg ne '') {
           $clonemsg = '<span class="LC_error">'.$clonemsg.'</span>';
               }
    }
    $outcome .= $clonemsg.$linefeed;
   
         if (!$can_clone) {          if (!$can_clone) {
     return (0,$outcome,$clonemsgref);      return (0,$outcome);
  }   }
     }      }
   
Line 16051  sub construct_course { Line 14852  sub construct_course {
                                              $args->{'ccuname'}.':'.                                               $args->{'ccuname'}.':'.
                                              $args->{'ccdomain'},                                               $args->{'ccdomain'},
                                              $args->{'crstype'},                                               $args->{'crstype'},
                                              $cnum,$context,$category,                                               $cnum,$context,$category);
                                              $callercontext);  
   
     # Note: The testing routines depend on this being output; see       # Note: The testing routines depend on this being output; see 
     # Utils::Course. This needs to at least be output as a comment      # Utils::Course. This needs to at least be output as a comment
     # if anyone ever decides to not show this, and Utils::Course::new      # if anyone ever decides to not show this, and Utils::Course::new
     # will need to be suitably modified.      # will need to be suitably modified.
     if (($callercontext eq 'auto') && ($user_lh ne '')) {      $outcome .= &mt('New LON-CAPA [_1] ID: [_2]',$crstype,$$courseid).$linefeed;
         $outcome .= &mt_user($user_lh,'New LON-CAPA [_1] ID: [_2]',$crstype,$$courseid).$linefeed;  
     } else {  
         $outcome .= &mt('New LON-CAPA [_1] ID: [_2]',$crstype,$$courseid).$linefeed;  
     }  
     if ($$courseid =~ /^error:/) {      if ($$courseid =~ /^error:/) {
         return (0,$outcome,$clonemsgref);          return (0,$outcome);
     }      }
   
 #  #
Line 16073  sub construct_course { Line 14869  sub construct_course {
     ($$crsudom,$$crsunum)= &LONCAPA::split_courseid($$courseid);      ($$crsudom,$$crsunum)= &LONCAPA::split_courseid($$courseid);
     my $crsuhome=&Apache::lonnet::homeserver($$crsunum,$$crsudom);      my $crsuhome=&Apache::lonnet::homeserver($$crsunum,$$crsudom);
     if ($crsuhome eq 'no_host') {      if ($crsuhome eq 'no_host') {
         if (($callercontext eq 'auto') && ($user_lh ne '')) {          $outcome .= &mt('Course creation failed, unrecognized course home server.').$linefeed;
             $outcome .= &mt_user($user_lh,          return (0,$outcome);
                             'Course creation failed, unrecognized course home server.');  
         } else {  
             $outcome .= &mt('Course creation failed, unrecognized course home server.');  
         }  
         $outcome .= $linefeed;  
         return (0,$outcome,$clonemsgref);  
     }      }
     $outcome .= &mt('Created on').': '.$crsuhome.$linefeed;      $outcome .= &mt('Created on').': '.$crsuhome.$linefeed;
   
 #  #
 # Do the cloning  # Do the cloning
 #  #   
     my @clonemsg;  
     if ($can_clone && $cloneid) {      if ($can_clone && $cloneid) {
         push(@clonemsg,   $clonemsg = &mt('Cloning [_1] from [_2]',$crstype,$clonehome);
                       {   if ($context ne 'auto') {
                           mt => 'Created [_1] by cloning from [_2]',      $clonemsg = '<span class="LC_success">'.$clonemsg.'</span>';
                           args => [$crstype,$clonetitle],   }
                       });   $outcome .= $clonemsg.$linefeed;
  my %oldcenv=&Apache::lonnet::dump('environment',$$crsudom,$$crsunum);   my %oldcenv=&Apache::lonnet::dump('environment',$$crsudom,$$crsunum);
 # Copy all files  # Copy all files
         my @info =   &Apache::lonclonecourse::copycoursefiles($cloneid,$$courseid,$args->{'datemode'},$args->{'dateshift'});
             &Apache::lonclonecourse::copycoursefiles($cloneid,$$courseid,$args->{'datemode'},  
                                                      $args->{'dateshift'},$args->{'crscode'},  
                                                      $args->{'ccuname'}.':'.$args->{'ccdomain'},  
                                                      $args->{'tinyurls'});  
         if (@info) {  
             push(@clonemsg,@info);  
         }  
 # Restore URL  # Restore URL
  $cenv{'url'}=$oldcenv{'url'};   $cenv{'url'}=$oldcenv{'url'};
 # Restore title  # Restore title
Line 16128  sub construct_course { Line 14910  sub construct_course {
                    'plc.users.denied',                     'plc.users.denied',
                    'hidefromcat',                     'hidefromcat',
                    'checkforpriv',                     'checkforpriv',
                    'categories'],                     'categories',
                      'internal.uniquecode'],
                    $$crsudom,$$crsunum);                     $$crsudom,$$crsunum);
         if ($args->{'textbook'}) {          if ($args->{'textbook'}) {
             $cenv{'internal.textbook'} = $args->{'textbook'};              $cenv{'internal.textbook'} = $args->{'textbook'};
Line 16178  sub construct_course { Line 14961  sub construct_course {
                 my $addcheck = &Apache::lonnet::auto_new_course($$crsunum,$$crsudom,$class,$cenv{'internal.courseowner'});                  my $addcheck = &Apache::lonnet::auto_new_course($$crsunum,$$crsudom,$class,$cenv{'internal.courseowner'});
                 $cenv{'internal.sectionnums'} .= $item.',';                  $cenv{'internal.sectionnums'} .= $item.',';
                 unless ($addcheck eq 'ok') {                  unless ($addcheck eq 'ok') {
                     push(@badclasses,$class);                      push @badclasses, $class;
                 }                  }
             }              }
             $cenv{'internal.sectionnums'} =~ s/,$//;              $cenv{'internal.sectionnums'} =~ s/,$//;
Line 16206  sub construct_course { Line 14989  sub construct_course {
                 my $addcheck =  &Apache::lonnet::auto_new_course($$crsunum,$$crsudom,$xl,$cenv{'internal.courseowner'});                  my $addcheck =  &Apache::lonnet::auto_new_course($$crsunum,$$crsudom,$xl,$cenv{'internal.courseowner'});
                 $cenv{'internal.crosslistings'} .= $item.',';                  $cenv{'internal.crosslistings'} .= $item.',';
                 unless ($addcheck eq 'ok') {                  unless ($addcheck eq 'ok') {
                     push(@badclasses,$xl);                      push @badclasses, $xl;
                 }                  }
             }              }
             $cenv{'internal.crosslistings'} =~ s/,$//;              $cenv{'internal.crosslistings'} =~ s/,$//;
Line 16241  sub construct_course { Line 15024  sub construct_course {
     }      }
     if (@badclasses > 0) {      if (@badclasses > 0) {
         my %lt=&Apache::lonlocal::texthash(          my %lt=&Apache::lonlocal::texthash(
                 'tclb' => 'The courses listed below were included as sections or crosslistings affiliated with your new LON-CAPA course.',                  'tclb' => 'The courses listed below were included as sections or crosslistings affiliated with your new LON-CAPA course.  However, if automated course roster updates are enabled for this class, these particular sections/crosslistings will not contribute towards enrollment, because the user identified as the course owner for this LON-CAPA course',
                 'howi' => 'However, if automated course roster updates are enabled for this class, these particular sections/crosslistings are not guaranteed to contribute towards enrollment.',                  'dnhr' => 'does not have rights to access enrollment in these classes',
                 'itis' => 'It is possible that rights to access enrollment for these classes will be available through assignment of co-owners.',                  'adby' => 'as determined by the policies of your institution on access to official classlists'
         );          );
         my $badclass_msg = $lt{'tclb'}.$linefeed.$lt{'howi'}.$linefeed.          my $badclass_msg = $cenv{'internal.courseowner'}.') - '.$lt{'dnhr'}.
                            &mt('That is because the user identified as the course owner ([_1]) does not have rights to access enrollment in these classes, as determined by the policies of your institution on access to official classlists',$cenv{'internal.courseowner'}).$linefeed.$lt{'itis'};                             ' ('.$lt{'adby'}.')';
         if ($context eq 'auto') {          if ($context eq 'auto') {
             $outcome .= $badclass_msg.$linefeed;              $outcome .= $badclass_msg.$linefeed;
         } else {  
             $outcome .= '<div class="LC_warning">'.$badclass_msg.$linefeed.'<ul>'."\n";              $outcome .= '<div class="LC_warning">'.$badclass_msg.$linefeed.'<ul>'."\n";
         }              foreach my $item (@badclasses) {
         foreach my $item (@badclasses) {                  if ($context eq 'auto') {
                       $outcome .= " - $item\n";
                   } else {
                       $outcome .= "<li>$item</li>\n";
                   }
               }
             if ($context eq 'auto') {              if ($context eq 'auto') {
                 $outcome .= " - $item\n";                  $outcome .= $linefeed;
             } else {              } else {
                 $outcome .= "<li>$item</li>\n";                  $outcome .= "</ul><br /><br /></div>\n";
             }              }
         }          } 
         if ($context eq 'auto') {  
             $outcome .= $linefeed;  
         } else {  
             $outcome .= "</ul><br /><br /></div>\n";  
         }  
     }      }
     if ($args->{'no_end_date'}) {      if ($args->{'no_end_date'}) {
         $args->{'endaccess'} = 0;          $args->{'endaccess'} = 0;
Line 16295  sub construct_course { Line 15077  sub construct_course {
        if ($args->{'setcontent'}) {         if ($args->{'setcontent'}) {
            $cenv{'question.email'}=$args->{'ccuname'}.':'.$args->{'ccdomain'};             $cenv{'question.email'}=$args->{'ccuname'}.':'.$args->{'ccdomain'};
        }         }
        if ($args->{'setcomment'}) {  
            $cenv{'comment.email'}=$args->{'ccuname'}.':'.$args->{'ccdomain'};  
        }  
     }      }
     if ($args->{'reshome'}) {      if ($args->{'reshome'}) {
  $cenv{'reshome'}=$args->{'reshome'}.'/';   $cenv{'reshome'}=$args->{'reshome'}.'/';
Line 16332  sub construct_course { Line 15111  sub construct_course {
             if (ref($crsinfo{$$crsudom.'_'.$$crsunum}) eq 'HASH') {              if (ref($crsinfo{$$crsudom.'_'.$$crsunum}) eq 'HASH') {
                 $crsinfo{$$crsudom.'_'.$$crsunum}{'uniquecode'} = $code;                  $crsinfo{$$crsudom.'_'.$$crsunum}{'uniquecode'} = $code;
                 my $putres = &Apache::lonnet::courseidput($$crsudom,\%crsinfo,$crsuhome,'notime');                  my $putres = &Apache::lonnet::courseidput($$crsudom,\%crsinfo,$crsuhome,'notime');
             }              } 
             if (ref($coderef)) {              if (ref($coderef)) {
                 $$coderef = $code;                  $$coderef = $code;
             }              }
Line 16369  sub construct_course { Line 15148  sub construct_course {
 # Open all assignments  # Open all assignments
 #  #
     if ($args->{'openall'}) {      if ($args->{'openall'}) {
        my $opendate = time;  
        if ($args->{'openallfrom'} =~ /^\d+$/) {  
            $opendate = $args->{'openallfrom'};  
        }  
        my $storeunder=$$crsudom.'_'.$$crsunum.'.0.opendate';         my $storeunder=$$crsudom.'_'.$$crsunum.'.0.opendate';
        my %storecontent = ($storeunder         => $opendate,         my %storecontent = ($storeunder         => time,
                            $storeunder.'.type' => 'date_start');                             $storeunder.'.type' => 'date_start');
        $outcome .= &mt('All assignments open starting [_1]',         
                        &Apache::lonlocal::locallocaltime($opendate)).': '.         $outcome .= &mt('Opening all assignments').': '.&Apache::lonnet::cput
                    &Apache::lonnet::cput                   ('resourcedata',\%storecontent,$$crsudom,$$crsunum).$linefeed;
                        ('resourcedata',\%storecontent,$$crsudom,$$crsunum).$linefeed;  
    }     }
 #  #
 # Set first page  # Set first page
 #  #
     unless (($args->{'nonstandard'}) || ($args->{'firstres'} eq 'blank')      unless (($args->{'nonstandard'}) || ($args->{'firstres'} eq 'blank')
     || ($cloneid)) {      || ($cloneid)) {
    use LONCAPA::map;
  $outcome .= &mt('Setting first resource').': ';   $outcome .= &mt('Setting first resource').': ';
   
  my $map = '/uploaded/'.$$crsudom.'/'.$$crsunum.'/default.sequence';   my $map = '/uploaded/'.$$crsudom.'/'.$$crsunum.'/default.sequence';
Line 16408  sub construct_course { Line 15183  sub construct_course {
         $outcome .= ($fatal?$errtext:'write ok').$linefeed;          $outcome .= ($fatal?$errtext:'write ok').$linefeed;
     }      }
   
     return (1,$outcome,\@clonemsg);      return (1,$outcome);
 }  }
   
 sub make_unique_code {  sub make_unique_code {
Line 16421  sub make_unique_code { Line 15196  sub make_unique_code {
     my $tries = 0;      my $tries = 0;
     my $gotlock = &Apache::lonnet::newput_dom('uniquecodes',$lockhash,$cdom);      my $gotlock = &Apache::lonnet::newput_dom('uniquecodes',$lockhash,$cdom);
     my ($code,$error);      my ($code,$error);
     
     while (($gotlock ne 'ok') && ($tries<3)) {      while (($gotlock ne 'ok') && ($tries<3)) {
         $tries ++;          $tries ++;
         sleep 1;          sleep 1;
Line 16577  sub compare_arrays { Line 15352  sub compare_arrays {
     return @difference;      return @difference;
 }  }
   
 sub lon_status_items {  
     my %defaults = (  
                      E         => 100,  
                      W         => 4,  
                      N         => 1,  
                      U         => 5,  
                      threshold => 200,  
                      sysmail   => 2500,  
                    );  
     my %names = (  
                    E => 'Errors',  
                    W => 'Warnings',  
                    N => 'Notices',  
                    U => 'Unsent',  
                 );  
     return (\%defaults,\%names);  
 }  
   
 # -------------------------------------------------------- Initialize user login  # -------------------------------------------------------- Initialize user login
 sub init_user_environment {  sub init_user_environment {
     my ($r, $username, $domain, $authhost, $form, $args) = @_;      my ($r, $username, $domain, $authhost, $form, $args) = @_;
Line 16630  sub init_user_environment { Line 15387  sub init_user_environment {
     opendir(DIR,$lonids);      opendir(DIR,$lonids);
     while ($filename=readdir(DIR)) {      while ($filename=readdir(DIR)) {
  if ($filename=~/^$username\_\d+\_$domain\_$authhost\.id$/) {   if ($filename=~/^$username\_\d+\_$domain\_$authhost\.id$/) {
                     if (tie(my %oldenv,'GDBM_File',"$lonids/$filename",      unlink($lonids.'/'.$filename);
                             &GDBM_READER(),0640)) {  
                         my $linkedfile;  
                         if (exists($oldenv{'user.linkedenv'})) {  
                             $linkedfile = $oldenv{'user.linkedenv'};  
                         }  
                         untie(%oldenv);  
                         if (unlink("$lonids/$filename")) {  
                             if ($linkedfile =~ /^[a-f0-9]+_linked$/) {  
                                 if (-l "$lonids/$linkedfile.id") {  
                                     unlink("$lonids/$linkedfile.id");  
                                 }  
                             }  
                         }  
                     } else {  
                         unlink($lonids.'/'.$filename);  
                     }  
  }   }
     }      }
     closedir(DIR);      closedir(DIR);
Line 16697  sub init_user_environment { Line 15438  sub init_user_environment {
 # --------------------------------------------------------- Write first profile  # --------------------------------------------------------- Write first profile
   
     {      {
         my $ip = &Apache::lonnet::get_requestor_ip();  
  my %initial_env =    my %initial_env = 
     ("user.name"          => $username,      ("user.name"          => $username,
      "user.domain"        => $domain,       "user.domain"        => $domain,
Line 16716  sub init_user_environment { Line 15456  sub init_user_environment {
      "request.course.sec" => '',       "request.course.sec" => '',
      "request.role"       => 'cm',       "request.role"       => 'cm',
      "request.role.adv"   => $env{'user.adv'},       "request.role.adv"   => $env{'user.adv'},
      "request.host"       => $ip,);       "request.host"       => $ENV{'REMOTE_ADDR'},);
   
         if ($form->{'localpath'}) {          if ($form->{'localpath'}) {
     $initial_env{"browser.localpath"}  = $form->{'localpath'};      $initial_env{"browser.localpath"}  = $form->{'localpath'};
Line 16735  sub init_user_environment { Line 15475  sub init_user_environment {
             $env{'user.noloadbalance'} = $lonhost;              $env{'user.noloadbalance'} = $lonhost;
         }          }
   
         if ($form->{'noloadbalance'}) {          my %is_adv = ( is_adv => $env{'user.adv'} );
             my @hosts = &Apache::lonnet::current_machine_ids();          my %domdef;
             my $hosthere = $form->{'noloadbalance'};  
             if (grep(/^\Q$hosthere\E$/,@hosts)) {  
                 $initial_env{"user.noloadbalance"} = $hosthere;  
                 $env{'user.noloadbalance'} = $hosthere;  
             }  
         }  
   
         unless ($domain eq 'public') {          unless ($domain eq 'public') {
             my %is_adv = ( is_adv => $env{'user.adv'} );              %domdef = &Apache::lonnet::get_domain_defaults($domain);
             my %domdef = &Apache::lonnet::get_domain_defaults($domain);          }
   
             foreach my $tool ('aboutme','blog','webdav','portfolio','timezone') {  
                 $userenv{'availabletools.'.$tool} =   
                     &Apache::lonnet::usertools_access($username,$domain,$tool,'reload',  
                                                       undef,\%userenv,\%domdef,\%is_adv);  
             }  
   
             foreach my $crstype ('official','unofficial','community','textbook') {          foreach my $tool ('aboutme','blog','webdav','portfolio') {
                 $userenv{'canrequest.'.$crstype} =              $userenv{'availabletools.'.$tool} = 
                     &Apache::lonnet::usertools_access($username,$domain,$crstype,                  &Apache::lonnet::usertools_access($username,$domain,$tool,'reload',
                                                       'reload','requestcourses',                                                    undef,\%userenv,\%domdef,\%is_adv);
                                                       \%userenv,\%domdef,\%is_adv);          }
             }  
   
             $userenv{'canrequest.author'} =          foreach my $crstype ('official','unofficial','community','textbook') {
                 &Apache::lonnet::usertools_access($username,$domain,'requestauthor',              $userenv{'canrequest.'.$crstype} =
                                                   'reload','requestauthor',                  &Apache::lonnet::usertools_access($username,$domain,$crstype,
                                                     'reload','requestcourses',
                                                   \%userenv,\%domdef,\%is_adv);                                                    \%userenv,\%domdef,\%is_adv);
             my %reqauthor = &Apache::lonnet::get('requestauthor',['author_status','author'],          }
                                                  $domain,$username);  
             my $reqstatus = $reqauthor{'author_status'};          $userenv{'canrequest.author'} =
             if ($reqstatus eq 'approval' || $reqstatus eq 'approved') {              &Apache::lonnet::usertools_access($username,$domain,'requestauthor',
                 if (ref($reqauthor{'author'}) eq 'HASH') {                                          'reload','requestauthor',
                     $userenv{'requestauthorqueued'} = $reqstatus.':'.                                          \%userenv,\%domdef,\%is_adv);
                                                       $reqauthor{'author'}{'timestamp'};          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'};
             }              }
         }          }
   
Line 16879  and quotacheck.pl Line 15611  and quotacheck.pl
   
 Inputs:  Inputs:
   
 filterlist - anonymous array of fields to include as potential filters  filterlist - anonymous array of fields to include as potential filters 
   
 crstype - course type  crstype - course type
   
 roleelement - fifth arg in selectcourse_link() populates fifth arg in javascript: opencrsbrowser() function, used  roleelement - fifth arg in selectcourse_link() populates fifth arg in javascript: opencrsbrowser() function, used
               to pop-open a course selector (will contain "extra element").                to pop-open a course selector (will contain "extra element"). 
   
 multelement - if multiple course selections will be allowed, this will be a hidden form element: name: multiple; value: 1  multelement - if multiple course selections will be allowed, this will be a hidden form element: name: multiple; value: 1
   
Line 16900  cloneruname - username of owner of new c Line 15632  cloneruname - username of owner of new c
   
 clonerudom - domain of owner of new course who wants to clone  clonerudom - domain of owner of new course who wants to clone
   
 typeelem - text to use for left column in row containing course type (i.e., Course, Community or Course/Community)  typeelem - text to use for left column in row containing course type (i.e., Course, Community or Course/Community) 
   
 codetitlesref - reference to array of titles of components in institutional codes (official courses)  codetitlesref - reference to array of titles of components in institutional codes (official courses)
   
 codedom - domain  codedom - domain
   
 formname - value of form element named "form".  formname - value of form element named "form". 
   
 fixeddom - domain, if fixed.  fixeddom - domain, if fixed.
   
 prevphase - value to assign to form element named "phase" when going back to the previous screen  prevphase - value to assign to form element named "phase" when going back to the previous screen  
   
 cnameelement - name of form element in form on opener page which will receive title of selected course  cnameelement - name of form element in form on opener page which will receive title of selected course 
   
 cnumelement - name of form element in form on opener page which will receive courseID  of selected course  cnumelement - name of form element in form on opener page which will receive courseID  of selected course
   
Line 17054  sub build_filters { Line 15786  sub build_filters {
         if (exists($filter->{'instcodefilter'})) {          if (exists($filter->{'instcodefilter'})) {
 #            if (($fixeddom) || ($formname eq 'requestcrs') ||  #            if (($fixeddom) || ($formname eq 'requestcrs') ||
 #                ($formname eq 'modifycourse') || ($formname eq 'filterpicker')) {  #                ($formname eq 'modifycourse') || ($formname eq 'filterpicker')) {
             if ($codedom) {              if ($codedom) { 
                 $officialjs = 1;                  $officialjs = 1;
                 ($instcodeform,$jscript,$$numtitlesref) =                  ($instcodeform,$jscript,$$numtitlesref) =
                     &Apache::courseclassifier::instcode_selectors($codedom,'filterpicker',                      &Apache::courseclassifier::instcode_selectors($codedom,'filterpicker',
Line 17183  $typeelement Line 15915  $typeelement
     return $jscript.$clonewarning.$output;      return $jscript.$clonewarning.$output;
 }  }
   
 =pod  =pod 
   
 =item * &timebased_select_form()  =item * &timebased_select_form()
   
Line 17198  item - name of form element (sincefilter Line 15930  item - name of form element (sincefilter
 filter - anonymous hash of criteria and their values  filter - anonymous hash of criteria and their values
   
 Returns: HTML for a select box contained a blank, then six time selections,  Returns: HTML for a select box contained a blank, then six time selections,
          with value set in incoming form variables currently selected.           with value set in incoming form variables currently selected. 
   
 Side Effects: None  Side Effects: None
   
Line 17235  page load completion for page showing se Line 15967  page load completion for page showing se
   
 Inputs: None  Inputs: None
   
 Returns: markup containing updateFilters() and hideSearching() javascript functions.  Returns: markup containing updateFilters() and hideSearching() javascript functions. 
   
 Side Effects: None  Side Effects: None
   
Line 17274  to retrieve a hash for which keys are co Line 16006  to retrieve a hash for which keys are co
   
 Inputs:  Inputs:
   
 dom - domain being searched  dom - domain being searched 
   
 type - course type ('Course' or 'Community' or '.' if any).  type - course type ('Course' or 'Community' or '.' if any).
   
Line 17286  cloneruname - optional username of new c Line 16018  cloneruname - optional username of new c
   
 clonerudom - optional domain of new course owner  clonerudom - optional domain of new course owner
   
 domcloner - optional "domcloner" flag; has value=1 if user has ccc priv in domain being filtered by,  domcloner - optional "domcloner" flag; has value=1 if user has ccc priv in domain being filtered by, 
             (used when DC is using course creation form)              (used when DC is using course creation form)
   
 codetitles - reference to array of titles of components in institutional codes (official courses).  codetitles - reference to array of titles of components in institutional codes (official courses).
Line 17296  cc_clone - escaped comma separated list Line 16028  cc_clone - escaped comma separated list
   
 reqcrsdom - domain of new course, where search_courses is used to identify potential courses to clone  reqcrsdom - domain of new course, where search_courses is used to identify potential courses to clone
   
 reqinstcode - institutional code of new course, where search_courses is used to identify potential  reqinstcode - institutional code of new course, where search_courses is used to identify potential 
               courses to clone                courses to clone 
   
 Returns: %courses - hash of courses satisfying search criteria, keys = course IDs, values are corresponding colon-separated escaped description, institutional code, owner and type.  Returns: %courses - hash of courses satisfying search criteria, keys = course IDs, values are corresponding colon-separated escaped description, institutional code, owner and type.
   
Line 17380  sub search_courses { Line 16112  sub search_courses {
                 if (ref($courses{$cid}) eq 'HASH') {                  if (ref($courses{$cid}) eq 'HASH') {
                     if (ref($courses{$cid}{roles}) eq 'ARRAY') {                      if (ref($courses{$cid}{roles}) eq 'ARRAY') {
                         if (!grep(/^\Q$courserole\E$/,@{$courses{$cid}{roles}})) {                          if (!grep(/^\Q$courserole\E$/,@{$courses{$cid}{roles}})) {
                             push(@{$courses{$cid}{roles}},$courserole);                              push (@{$courses{$cid}{roles}},$courserole);
                         }                          }
                     } else {                      } else {
                         $courses{$cid}{roles} = [$courserole];                          $courses{$cid}{roles} = [$courserole];
Line 17423  $required - LON-CAPA version needed by c Line 16155  $required - LON-CAPA version needed by c
   
 Returns:  Returns:
   
 $switchserver - query string tp append to /adm/switchserver call (if  $switchserver - query string tp append to /adm/switchserver call (if 
                 current server's LON-CAPA version is too old.                  current server's LON-CAPA version is too old. 
   
 $warning - Message is displayed if no suitable server could be found.  $warning - Message is displayed if no suitable server could be found.
   
Line 17537  Inputs: Line 16269  Inputs:
 $loncaparev - Version on current server (format: Major.Minor.Subrelease-datestamp)  $loncaparev - Version on current server (format: Major.Minor.Subrelease-datestamp)
   
 $interval (optional) - Time which may elapse (in s) between last check for content  $interval (optional) - Time which may elapse (in s) between last check for content
                        change in current course. (default: 600 s).                         change in current course. (default: 600 s).  
   
 Returns: an array; first element is:  Returns: an array; first element is:
   
Line 17545  Returns: an array; first element is: Line 16277  Returns: an array; first element is:
   
 'switch' - if content updates mean user's session  'switch' - if content updates mean user's session
            needs to be switched to a server running a newer LON-CAPA version             needs to be switched to a server running a newer LON-CAPA version
    
 'update' - if course session needs to be refreshed (i.e., Big Hash needs to be reloaded)  'update' - if course session needs to be refreshed (i.e., Big Hash needs to be reloaded)
            on current server hosting user's session             on current server hosting user's session                
   
 ''       - if no action required.  ''       - if no action required.
   
Line 17555  Returns: an array; first element is: Line 16287  Returns: an array; first element is:
   
 If first item element is 'switch':  If first item element is 'switch':
   
 second item is $switchwarning - Warning message if no suitable server found to host session.  second item is $switchwarning - Warning message if no suitable server found to host session. 
   
 third item is $switchserver - query string to append to /adm/switchserver containing lonHostID  third item is $switchserver - query string to append to /adm/switchserver containing lonHostID
                               and current role.                                and current role. 
   
 otherwise: no other elements returned.  otherwise: no other elements returned.
   
Line 17576  sub needs_coursereinit { Line 16308  sub needs_coursereinit {
         $interval = 600;          $interval = 600;
     }      }
     if (($now-$env{'request.course.timechecked'})>$interval) {      if (($now-$env{'request.course.timechecked'})>$interval) {
           my $lastchange = &Apache::lonnet::get_coursechange($cdom,$cnum);
         &Apache::lonnet::appenv({'request.course.timechecked'=>$now});          &Apache::lonnet::appenv({'request.course.timechecked'=>$now});
         my $blocked = &blocking_status('reinit',undef,$cnum,$cdom,undef,1);          if ($lastchange > $env{'request.course.tied'}) {
         if ($blocked) {              my %curr_reqd_hash = &Apache::lonnet::userenvironment($cdom,$cnum,'internal.releaserequired');
             return ();              if ($curr_reqd_hash{'internal.releaserequired'} ne '') {
         }                  my $required = $env{'course.'.$cdom.'_'.$cnum.'.internal.releaserequired'};
         my $update;                  if ($curr_reqd_hash{'internal.releaserequired'} ne $required) {
         my $lastmainchange = &Apache::lonnet::get_coursechange($cdom,$cnum);                      &Apache::lonnet::appenv({'course.'.$cdom.'_'.$cnum.'.internal.releaserequired' =>
         my $lastsuppchange = &Apache::lonnet::get_suppchange($cdom,$cnum);                                               $curr_reqd_hash{'internal.releaserequired'}});
         if ($lastmainchange > $env{'request.course.tied'}) {                      my ($switchserver,$switchwarning) =
             my ($needswitch,$switchwarning,$switchserver) = &switch_for_update($loncaparev,$cdom,$cnum);                          &check_release_required($loncaparev,$cdom.'_'.$cnum,$env{'request.role'},
             if ($needswitch) {                                                  $curr_reqd_hash{'internal.releaserequired'});
                 return ('switch',$switchwarning,$switchserver);                      if ($switchwarning ne '' || $switchserver ne '') {
             }                          return ('switch',$switchwarning,$switchserver);
             $update = 'main';                      }
         }  
         if ($lastsuppchange > $env{'request.course.suppupdated'}) {  
             if ($update) {  
                 $update = 'both';  
             } else {  
                 my ($needswitch,$switchwarning,$switchserver) = &switch_for_update($loncaparev,$cdom,$cnum);  
                 if ($needswitch) {  
                     return ('switch',$switchwarning,$switchserver);  
                 } else {  
                     $update = 'supp';  
                 }                  }
             }              }
             return ($update);              return ('update');
         }  
     }  
     return ();  
 }  
   
 sub switch_for_update {  
     my ($loncaparev,$cdom,$cnum) = @_;  
     my %curr_reqd_hash = &Apache::lonnet::userenvironment($cdom,$cnum,'internal.releaserequired');  
     if ($curr_reqd_hash{'internal.releaserequired'} ne '') {  
         my $required = $env{'course.'.$cdom.'_'.$cnum.'.internal.releaserequired'};  
         if ($curr_reqd_hash{'internal.releaserequired'} ne $required) {  
             &Apache::lonnet::appenv({'course.'.$cdom.'_'.$cnum.'.internal.releaserequired' =>  
                                     $curr_reqd_hash{'internal.releaserequired'}});  
             my ($switchserver,$switchwarning) =  
                 &check_release_required($loncaparev,$cdom.'_'.$cnum,$env{'request.role'},  
                                         $curr_reqd_hash{'internal.releaserequired'});  
             if ($switchwarning ne '' || $switchserver ne '') {  
                 return ('switch',$switchwarning,$switchserver);  
             }  
         }          }
     }      }
     return ();      return ();
Line 17633  sub update_content_constraints { Line 16337  sub update_content_constraints {
     my ($reqdmajor,$reqdminor) = split(/\./,$curr_reqd_hash{'internal.releaserequired'});      my ($reqdmajor,$reqdminor) = split(/\./,$curr_reqd_hash{'internal.releaserequired'});
     my %checkresponsetypes;      my %checkresponsetypes;
     foreach my $key (keys(%Apache::lonnet::needsrelease)) {      foreach my $key (keys(%Apache::lonnet::needsrelease)) {
         my ($item,$name,$value) = split(/:/,$key);          my ($item,$name,$value,$valmatch) = split(/:/,$key);
         if ($item eq 'resourcetag') {          if ($item eq 'resourcetag') {
             if ($name eq 'responsetype') {              if ($name eq 'responsetype') {
                 $checkresponsetypes{$value} = $Apache::lonnet::needsrelease{$key}                  $checkresponsetypes{$value} = $Apache::lonnet::needsrelease{$key}
Line 17713  sub parse_supplemental_title { Line 16417  sub parse_supplemental_title {
     return $title;      return $title;
 }  }
   
 sub get_supplemental {  
     my ($cnum,$cdom,$ignorecache,$possdel)=@_;  
     my $hashid=$cnum.':'.$cdom;  
     my ($supplemental,$cached,$set_httprefs);  
     unless ($ignorecache) {  
         ($supplemental,$cached) = &Apache::lonnet::is_cached_new('supplemental',$hashid);  
     }  
     unless (defined($cached)) {  
         my $chome=&Apache::lonnet::homeserver($cnum,$cdom);  
         unless ($chome eq 'no_host') {  
             my @order = @LONCAPA::map::order;  
             my @resources = @LONCAPA::map::resources;  
             my @resparms = @LONCAPA::map::resparms;  
             my @zombies = @LONCAPA::map::zombies;  
             my ($errors,%ids,%hidden);  
             $errors =  
                 &recurse_supplemental($cnum,$cdom,'supplemental.sequence',  
                                       $errors,$possdel,\%ids,\%hidden);  
             @LONCAPA::map::order = @order;  
             @LONCAPA::map::resources = @resources;  
             @LONCAPA::map::resparms = @resparms;  
             @LONCAPA::map::zombies = @zombies;  
             $set_httprefs = 1;  
             if ($env{'request.course.id'} eq $cdom.'_'.$cnum) {  
                 &Apache::lonnet::appenv({'request.course.suppupdated' => time});  
             }  
             $supplemental = {  
                                ids => \%ids,  
                                hidden => \%hidden,  
                             };  
             &Apache::lonnet::do_cache_new('supplemental',$hashid,$supplemental,600);  
         }  
     }  
     return ($supplemental,$set_httprefs);  
 }  
   
 sub recurse_supplemental {  sub recurse_supplemental {
     my ($cnum,$cdom,$suppmap,$errors,$possdel,$suppids,$hiddensupp,$hidden) = @_;      my ($cnum,$cdom,$suppmap,$numfiles,$errors) = @_;
     if (($suppmap) && (ref($suppids) eq 'HASH') && (ref($hiddensupp) eq 'HASH')) {      if ($suppmap) {
         my $mapnum;  
         if ($suppmap eq 'supplemental.sequence') {  
             $mapnum = 0;  
         } else {  
             ($mapnum) = ($suppmap =~ /^supplemental_(\d+)\.sequence$/);  
         }  
         my ($errtext,$fatal) = &LONCAPA::map::mapread('/uploaded/'.$cdom.'/'.$cnum.'/'.$suppmap);          my ($errtext,$fatal) = &LONCAPA::map::mapread('/uploaded/'.$cdom.'/'.$cnum.'/'.$suppmap);
         if ($fatal) {          if ($fatal) {
             $errors ++;              $errors ++;
         } else {          } else {
             my @order = @LONCAPA::map::order;              if ($#LONCAPA::map::resources > 0) {
             if (@order > 0) {                  foreach my $res (@LONCAPA::map::resources) {
                 my @resources = @LONCAPA::map::resources;                      my ($title,$src,$ext,$type,$status)=split(/\:/,$res);
                 my @resparms = @LONCAPA::map::resparms;  
                 foreach my $idx (@order) {  
                     my ($title,$src,$ext,$type,$status)=split(/\:/,$resources[$idx]);  
                     if (($src ne '') && ($status eq 'res')) {                      if (($src ne '') && ($status eq 'res')) {
                         my $id = $mapnum.':'.$idx;  
                         push(@{$suppids->{$src}},$id);  
                         if (($hidden) || (&get_supp_parameter($resparms[$idx],'parameter_hiddenresource') =~ /^yes/i)) {  
                             $hiddensupp->{$id} = 1;  
                         }  
                         if ($src =~ m{^\Q/uploaded/$cdom/$cnum/\E(supplemental_\d+\.sequence)$}) {                          if ($src =~ m{^\Q/uploaded/$cdom/$cnum/\E(supplemental_\d+\.sequence)$}) {
                             $errors = &recurse_supplemental($cnum,$cdom,$1,$errors,$possdel,$suppids,                              ($numfiles,$errors) = &recurse_supplemental($cnum,$cdom,$1,$numfiles,$errors);
                                                             $hiddensupp,$hiddensupp->{$id});  
                         } else {                          } else {
                             my $allowed;                              $numfiles ++;
                             if (($env{'request.role.adv'}) || (!$hiddensupp->{$id})) {  
                                 $allowed = 1;  
                             } elsif ($possdel) {  
                                 foreach my $item (@{$suppids->{$src}}) {  
                                     next if ($item eq $id);  
                                     unless ($hiddensupp->{$item}) {  
                                        $allowed = 1;  
                                        last;  
                                     }  
                                 }  
                                 if ((!$allowed) && (exists($env{'httpref.'.$src}))) {  
                                     &Apache::lonnet::delenv('httpref.'.$src);  
                                 }  
                             }  
                             if ($allowed && (!exists($env{'httpref.'.$src}))) {  
                                 &Apache::lonnet::allowuploaded('/adm/coursedoc',$src);  
                             }  
                         }                          }
                     }                      }
                 }                  }
             }              }
         }          }
     }      }
     return $errors;      return ($numfiles,$errors);
 }  
   
 sub set_supp_httprefs {  
     my ($cnum,$cdom,$supplemental,$possdel) = @_;  
     if (ref($supplemental) eq 'HASH') {  
         if ((ref($supplemental->{'ids'}) eq 'HASH') && (ref($supplemental->{'hidden'}) eq 'HASH')) {  
             foreach my $src (keys(%{$supplemental->{'ids'}})) {  
                 next if ($src =~ /\.sequence$/);  
                 if (ref($supplemental->{'ids'}->{$src}) eq 'ARRAY') {  
                     my $allowed;  
                     if ($env{'request.role.adv'}) {  
                         $allowed = 1;  
                     } else {  
                         foreach my $id (@{$supplemental->{'ids'}->{$src}}) {  
                             unless ($supplemental->{'hidden'}->{$id}) {  
                                 $allowed = 1;  
                                 last;  
                             }  
                         }  
                     }  
                     if (exists($env{'httpref.'.$src})) {  
                         if ($possdel) {  
                             unless ($allowed) {  
                                 &Apache::lonnet::delenv('httpref.'.$src);  
                             }  
                         }  
                     } elsif ($allowed) {  
                         &Apache::lonnet::allowuploaded('/adm/coursedoc',$src);  
                     }  
                 }  
             }  
             if ($env{'request.course.id'} eq $cdom.'_'.$cnum) {  
                 &Apache::lonnet::appenv({'request.course.suppupdated' => time});  
             }  
         }  
     }  
 }  
   
 sub get_supp_parameter {  
     my ($resparm,$name)=@_;  
     return if ($resparm eq '');  
     my $value=undef;  
     my $ptype=undef;  
     foreach (split('&&&',$resparm)) {  
         my ($thistype,$thisname,$thisvalue)=split('___',$_);  
         if ($thisname eq $name) {  
             $value=$thisvalue;  
             $ptype=$thistype;  
         }  
     }  
     return $value;  
 }  }
   
 sub symb_to_docspath {  sub symb_to_docspath {
     my ($symb,$navmapref) = @_;      my ($symb) = @_;
     return unless ($symb && ref($navmapref));      return unless ($symb);
     my ($mapurl,$id,$resurl) = &Apache::lonnet::decode_symb($symb);      my ($mapurl,$id,$resurl) = &Apache::lonnet::decode_symb($symb);
     if ($resurl=~/\.(sequence|page)$/) {      if ($resurl=~/\.(sequence|page)$/) {
         $mapurl=$resurl;          $mapurl=$resurl;
Line 17866  sub symb_to_docspath { Line 16451  sub symb_to_docspath {
         $mapurl=$env{'course.'.$env{'request.course.id'}.'.url'};          $mapurl=$env{'course.'.$env{'request.course.id'}.'.url'};
     }      }
     my $mapresobj;      my $mapresobj;
     unless (ref($$navmapref)) {      my $navmap = Apache::lonnavmaps::navmap->new();
         $$navmapref = Apache::lonnavmaps::navmap->new();      if (ref($navmap)) {
     }          $mapresobj = $navmap->getResourceByUrl($mapurl);
     if (ref($$navmapref)) {  
         $mapresobj = $$navmapref->getResourceByUrl($mapurl);  
     }      }
     $mapurl=~s{^.*/([^/]+)\.(\w+)$}{$1};      $mapurl=~s{^.*/([^/]+)\.(\w+)$}{$1};
     my $type=$2;      my $type=$2;
Line 17880  sub symb_to_docspath { Line 16463  sub symb_to_docspath {
         if ($pcslist ne '') {          if ($pcslist ne '') {
             foreach my $pc (split(/,/,$pcslist)) {              foreach my $pc (split(/,/,$pcslist)) {
                 next if ($pc <= 1);                  next if ($pc <= 1);
                 my $res = $$navmapref->getByMapPc($pc);                  my $res = $navmap->getByMapPc($pc);
                 if (ref($res)) {                  if (ref($res)) {
                     my $thisurl = $res->src();                      my $thisurl = $res->src();
                     $thisurl=~s{^.*/([^/]+)\.\w+$}{$1};                      $thisurl=~s{^.*/([^/]+)\.\w+$}{$1};
Line 17926  sub symb_to_docspath { Line 16509  sub symb_to_docspath {
     return $path;      return $path;
 }  }
   
 sub validate_folderpath {  
     my ($supplementalflag,$allowed,$coursenum,$coursedom) = @_;  
     if ($env{'form.folderpath'} ne '') {  
         my @items = split(/\&/,$env{'form.folderpath'});  
         my ($badpath,$changed,$got_supp,$supppath,%supphidden,%suppids);  
         for (my $i=0; $i<@items; $i++) {  
             my $odd = $i%2;  
             if (($odd) && (!$supplementalflag) && ($items[$i] !~ /^[^:]*:(|\d+):(|1):(|1):(|1):(|1)$/)) {  
                 $badpath = 1;  
             } elsif ($odd && $supplementalflag) {  
                 my $idx = $i-1;  
                 if ($items[$i] =~ /^([^:]*)::(|1):::$/) {  
                     my $esc_name = $1;  
                     if ((!$allowed) || ($items[$idx] eq 'supplemental')) {  
                         $supppath .= '&'.$esc_name;  
                         $changed = 1;  
                     } else {  
                         $supppath .= '&'.$items[$i];  
                     }  
                 } elsif (($allowed) && ($items[$idx] ne 'supplemental')) {  
                     $changed = 1;  
                     my $is_hidden;  
                     unless ($got_supp) {  
                         my ($supplemental) = &get_supplemental($coursenum,$coursedom);  
                         if (ref($supplemental) eq 'HASH') {  
                             if (ref($supplemental->{'hidden'}) eq 'HASH') {  
                                 %supphidden = %{$supplemental->{'hidden'}};  
                             }  
                             if (ref($supplemental->{'ids'}) eq 'HASH') {  
                                 %suppids = %{$supplemental->{'ids'}};  
                             }  
                         }  
                         $got_supp = 1;  
                     }  
                     if (ref($suppids{"/uploaded/$coursedom/$coursenum/$items[$idx].sequence"}) eq 'ARRAY') {  
                         my $mapid = $suppids{"/uploaded/$coursedom/$coursenum/$items[$idx].sequence"}->[0];  
                         if ($supphidden{$mapid}) {  
                             $is_hidden = 1;  
                         }  
                     }  
                     $supppath .= '&'.$items[$i].'::'.$is_hidden.':::';  
                 } else {  
                     $supppath .= '&'.$items[$i];  
                 }  
             } elsif ((!$odd) && ($items[$i] !~ /^(default|supplemental)(|_\d+)$/)) {  
                 $badpath = 1;  
             } elsif ($supplementalflag) {  
                 $supppath .= '&'.$items[$i];  
             }  
             last if ($badpath);  
         }  
         if ($badpath) {  
             delete($env{'form.folderpath'});  
         } elsif ($changed && $supplementalflag) {  
             $supppath =~ s/^\&//;  
             $env{'form.folderpath'} = $supppath;  
         }  
     }  
     return;  
 }  
   
 sub captcha_display {  sub captcha_display {
     my ($context,$lonhost,$defdom) = @_;      my ($context,$lonhost) = @_;
     my ($output,$error);      my ($output,$error);
     my ($captcha,$pubkey,$privkey,$version) =      my ($captcha,$pubkey,$privkey,$version) = 
         &get_captcha_config($context,$lonhost,$defdom);          &get_captcha_config($context,$lonhost);
     if ($captcha eq 'original') {      if ($captcha eq 'original') {
         $output = &create_captcha();          $output = &create_captcha();
         unless ($output) {          unless ($output) {
Line 18007  sub captcha_display { Line 16529  sub captcha_display {
 }  }
   
 sub captcha_response {  sub captcha_response {
     my ($context,$lonhost,$defdom) = @_;      my ($context,$lonhost) = @_;
     my ($captcha_chk,$captcha_error);      my ($captcha_chk,$captcha_error);
     my ($captcha,$pubkey,$privkey,$version) = &get_captcha_config($context,$lonhost,$defdom);      my ($captcha,$pubkey,$privkey,$version) = &get_captcha_config($context,$lonhost);
     if ($captcha eq 'original') {      if ($captcha eq 'original') {
         ($captcha_chk,$captcha_error) = &check_captcha();          ($captcha_chk,$captcha_error) = &check_captcha();
     } elsif ($captcha eq 'recaptcha') {      } elsif ($captcha eq 'recaptcha') {
Line 18021  sub captcha_response { Line 16543  sub captcha_response {
 }  }
   
 sub get_captcha_config {  sub get_captcha_config {
     my ($context,$lonhost,$dom_in_effect) = @_;      my ($context,$lonhost) = @_;
     my ($captcha,$pubkey,$privkey,$version,$hashtocheck);      my ($captcha,$pubkey,$privkey,$version,$hashtocheck);
     my $hostname = &Apache::lonnet::hostname($lonhost);      my $hostname = &Apache::lonnet::hostname($lonhost);
     my $serverhomeID = &Apache::lonnet::get_server_homeID($hostname);      my $serverhomeID = &Apache::lonnet::get_server_homeID($hostname);
Line 18061  sub get_captcha_config { Line 16583  sub get_captcha_config {
                 $captcha = 'recaptcha';                  $captcha = 'recaptcha';
                 $version = $domconfhash{$serverhomedom.'.login.recaptchaversion'};                  $version = $domconfhash{$serverhomedom.'.login.recaptchaversion'};
                 if ($version ne '2') {                  if ($version ne '2') {
                     $version = 1;                      $version = 1; 
                 }                  }
             } else {              } else {
                 $captcha = 'original';                  $captcha = 'original';
Line 18069  sub get_captcha_config { Line 16591  sub get_captcha_config {
         } elsif ($domconfhash{$serverhomedom.'.login.captcha'} eq 'original') {          } elsif ($domconfhash{$serverhomedom.'.login.captcha'} eq 'original') {
             $captcha = 'original';              $captcha = 'original';
         }          }
     } elsif ($context eq 'passwords') {  
         if ($dom_in_effect) {  
             my %passwdconf = &Apache::lonnet::get_passwdconf($dom_in_effect);  
             if ($passwdconf{'captcha'} eq 'recaptcha') {  
                 if (ref($passwdconf{'recaptchakeys'}) eq 'HASH') {  
                     $pubkey = $passwdconf{'recaptchakeys'}{'public'};  
                     $privkey = $passwdconf{'recaptchakeys'}{'private'};  
                 }  
                 if ($privkey && $pubkey) {  
                     $captcha = 'recaptcha';  
                     $version = $passwdconf{'recaptchaversion'};  
                     if ($version ne '2') {  
                         $version = 1;  
                     }  
                 } else {  
                     $captcha = 'original';  
                 }  
             } elsif ($passwdconf{'captcha'} ne 'notused') {  
                 $captcha = 'original';  
             }  
         }  
     }      }
     return ($captcha,$pubkey,$privkey,$version);      return ($captcha,$pubkey,$privkey,$version);
 }  }
Line 18107  sub create_captcha { Line 16608  sub create_captcha {
   
         if (-e $Apache::lonnet::perlvar{'lonCaptchaDir'}.'/'.$md5sum.'.png') {          if (-e $Apache::lonnet::perlvar{'lonCaptchaDir'}.'/'.$md5sum.'.png') {
             $output = '<input type="hidden" name="crypt" value="'.$md5sum.'" />'."\n".              $output = '<input type="hidden" name="crypt" value="'.$md5sum.'" />'."\n".
                       '<span class="LC_nobreak">'.  
                       &mt('Type in the letters/numbers shown below').'&nbsp;'.                        &mt('Type in the letters/numbers shown below').'&nbsp;'.
                       '<input type="text" size="5" name="code" value="" autocomplete="off" />'.                        '<input type="text" size="5" name="code" value="" autocomplete="off" />'.
                       '</span><br />'.                        '<br />'.
                       '<img src="'.$captcha_params{'www_output_dir'}.'/'.$md5sum.'.png" alt="captcha" />';                        '<img src="'.$captcha_params{'www_output_dir'}.'/'.$md5sum.'.png" alt="captcha" />';
             last;              last;
         }          }
     }      }
     if ($output eq '') {  
         &Apache::lonnet::logthis("Failed to create Captcha code after $tries attempts.");  
     }  
     return $output;      return $output;
 }  }
   
Line 18156  sub check_captcha { Line 16653  sub check_captcha {
 sub create_recaptcha {  sub create_recaptcha {
     my ($pubkey,$version) = @_;      my ($pubkey,$version) = @_;
     if ($version >= 2) {      if ($version >= 2) {
         return '<div class="g-recaptcha" data-sitekey="'.$pubkey.'"></div>'.          return '<div class="g-recaptcha" data-sitekey="'.$pubkey.'"></div>';
                '<div style="padding:0;clear:both;margin:0;border:0"></div>';  
     } else {      } else {
         my $use_ssl;          my $use_ssl;
         if ($ENV{'SERVER_PORT'} == 443) {          if ($ENV{'SERVER_PORT'} == 443) {
Line 18169  sub create_recaptcha { Line 16665  sub create_recaptcha {
                &mt('If the text is hard to read, [_1] will replace them.',                 &mt('If the text is hard to read, [_1] will replace them.',
                    '<img src="/res/adm/pages/refresh.gif" alt="reCAPTCHA refresh" />').                     '<img src="/res/adm/pages/refresh.gif" alt="reCAPTCHA refresh" />').
                '<br /><br />';                 '<br /><br />';
      }      }
 }  }
   
 sub check_recaptcha {  sub check_recaptcha {
     my ($privkey,$version) = @_;      my ($privkey,$version) = @_;
     my $captcha_chk;      my $captcha_chk;
     my $ip = &Apache::lonnet::get_requestor_ip();   
     if ($version >= 2) {      if ($version >= 2) {
         my $ua = LWP::UserAgent->new;          my $ua = LWP::UserAgent->new;
         $ua->timeout(10);          $ua->timeout(10);
         my %info = (          my %info = (
                      secret   => $privkey,                       secret   => $privkey, 
                      response => $env{'form.g-recaptcha-response'},                       response => $env{'form.g-recaptcha-response'},
                      remoteip => $ip,                       remoteip => $ENV{'REMOTE_ADDR'},
                    );                     );
         my $response = $ua->post('https://www.google.com/recaptcha/api/siteverify',\%info);          my $response = $ua->post('https://www.google.com/recaptcha/api/siteverify',\%info);
         if ($response->is_success)  {          if ($response->is_success)  {
Line 18198  sub check_recaptcha { Line 16693  sub check_recaptcha {
         my $captcha_result =          my $captcha_result =
             $captcha->check_answer(              $captcha->check_answer(
                                     $privkey,                                      $privkey,
                                     $ip,                                      $ENV{'REMOTE_ADDR'},
                                     $env{'form.recaptcha_challenge_field'},                                      $env{'form.recaptcha_challenge_field'},
                                     $env{'form.recaptcha_response_field'},                                      $env{'form.recaptcha_response_field'},
                                   );                                    );
Line 18210  sub check_recaptcha { Line 16705  sub check_recaptcha {
 }  }
   
 sub emailusername_info {  sub emailusername_info {
     my @fields = ('firstname','lastname','institution','web','location','officialemail','id');      my @fields = ('firstname','lastname','institution','web','location','officialemail');
     my %titles = &Apache::lonlocal::texthash (      my %titles = &Apache::lonlocal::texthash (
                      lastname      => 'Last Name',                       lastname      => 'Last Name',
                      firstname     => 'First Name',                       firstname     => 'First Name',
Line 18218  sub emailusername_info { Line 16713  sub emailusername_info {
                      location      => "School's city, state/province, country",                       location      => "School's city, state/province, country",
                      web           => "School's web address",                       web           => "School's web address",
                      officialemail => 'E-mail address at institution (if different)',                       officialemail => 'E-mail address at institution (if different)',
                      id            => 'Student/Employee ID',  
                  );                   );
     return (\@fields,\%titles);      return (\@fields,\%titles);
 }  }
Line 18247  sub cleanup_html { Line 16741  sub cleanup_html {
   
 # Checks for critical messages and returns a redirect url if one exists.  # Checks for critical messages and returns a redirect url if one exists.
 # $interval indicates how often to check for messages.  # $interval indicates how often to check for messages.
 # $context is the calling context -- roles, grades, contents, menu or flip.  
 sub critical_redirect {  sub critical_redirect {
     my ($interval,$context) = @_;      my ($interval) = @_;
     unless (($env{'user.domain'} ne '') && ($env{'user.name'} ne '')) {  
         return ();  
     }  
     if ((time-$env{'user.criticalcheck.time'})>$interval) {      if ((time-$env{'user.criticalcheck.time'})>$interval) {
         if (($env{'request.course.id'}) && (($context eq 'flip') || ($context eq 'contents'))) {          my @what=&Apache::lonnet::dump('critical', $env{'user.domain'}, 
             my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};  
             my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};  
             my $blocked = &blocking_status('alert',undef,$cnum,$cdom,undef,1);  
             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})) {  
                     return;  
                 }  
             }  
         }  
         my @what=&Apache::lonnet::dump('critical', $env{'user.domain'},  
                                         $env{'user.name'});                                          $env{'user.name'});
         &Apache::lonnet::appenv({'user.criticalcheck.time'=>time});          &Apache::lonnet::appenv({'user.criticalcheck.time'=>time});
         my $redirecturl;          my $redirecturl;
         if ($what[0]) {          if ($what[0]) {
             if (($what[0] ne 'con_lost') && ($what[0] ne 'no_such_host') && ($what[0]!~/^error\:/)) {      if (($what[0] ne 'con_lost') && ($what[0]!~/^error\:/)) {
                 $redirecturl='/adm/email?critical=display';          $redirecturl='/adm/email?critical=display';
                 my $url=&Apache::lonnet::absolute_url().$redirecturl;          my $url=&Apache::lonnet::absolute_url().$redirecturl;
                 return (1, $url);                  return (1, $url);
             }              }
         }          }
     }      } 
     return ();      return ();
 }  }
   
Line 18334  sub des_decrypt { Line 16809  sub des_decrypt {
     return $plaintext;      return $plaintext;
 }  }
   
 sub get_requested_shorturls {  
     my ($cdom,$cnum,$navmap) = @_;  
     return unless (ref($navmap));  
     my ($numnew,$errors);  
     my @toshorten = &Apache::loncommon::get_env_multiple('form.addtiny');  
     if (@toshorten) {  
         my (%maps,%resources,%titles);  
         &Apache::loncourserespicker::enumerate_course_contents($navmap,\%maps,\%resources,\%titles,  
                                                                'shorturls',$cdom,$cnum);  
         if (keys(%resources)) {  
             my %tocreate;  
             foreach my $item (sort {$a <=> $b} (@toshorten)) {  
                 my $symb = $resources{$item};  
                 if ($symb) {  
                     $tocreate{$cnum.'&'.$symb} = 1;  
                 }  
             }  
             if (keys(%tocreate)) {  
                 ($numnew,$errors) = &make_short_symbs($cdom,$cnum,  
                                                       \%tocreate);  
             }  
         }  
     }  
     return ($numnew,$errors);  
 }  
   
 sub make_short_symbs {  
     my ($cdom,$cnum,$tocreateref,$lockuser) = @_;  
     my ($numnew,@errors);  
     if (ref($tocreateref) eq 'HASH') {  
         my %tocreate = %{$tocreateref};  
         if (keys(%tocreate)) {  
             my %coursetiny = &Apache::lonnet::dump('tiny',$cdom,$cnum);  
             my $su = Short::URL->new(no_vowels => 1);  
             my $init = '';  
             my (%newunique,%addcourse,%courseonly,%failed);  
             # get lock on tiny db  
             my $now = time;  
             if ($lockuser eq '') {  
                 $lockuser = $env{'user.name'}.':'.$env{'user.domain'};  
             }  
             my $lockhash = {  
                                 "lock\0$now" => $lockuser,  
                             };  
             my $tries = 0;  
             my $gotlock = &Apache::lonnet::newput_dom('tiny',$lockhash,$cdom);  
             my ($code,$error);  
             while (($gotlock ne 'ok') && ($tries<3)) {  
                 $tries ++;  
                 sleep 1;  
                 $gotlock = &Apache::lonnet::newput_dom('tiny',$lockhash,$cdom);  
             }  
             if ($gotlock eq 'ok') {  
                 $init = &shorten_symbs($cdom,$init,$su,\%coursetiny,\%tocreate,\%newunique,  
                                        \%addcourse,\%courseonly,\%failed);  
                 if (keys(%failed)) {  
                     my $numfailed = scalar(keys(%failed));  
                     push(@errors,&mt('error: could not obtain unique six character URL for [quant,_1,resource]',$numfailed));  
                 }  
                 if (keys(%newunique)) {  
                     my $putres = &Apache::lonnet::newput_dom('tiny',\%newunique,$cdom);  
                     if ($putres eq 'ok') {  
                         $numnew = scalar(keys(%newunique));  
                         my $newputres = &Apache::lonnet::newput('tiny',\%addcourse,$cdom,$cnum);  
                         unless ($newputres eq 'ok') {  
                             push(@errors,&mt('error: could not store course look-up of short URLs'));  
                         }  
                     } else {  
                         push(@errors,&mt('error: could not store unique six character URLs'));  
                     }  
                 }  
                 my $dellockres = &Apache::lonnet::del_dom('tiny',["lock\0$now"],$cdom);  
                 unless ($dellockres eq 'ok') {  
                     push(@errors,&mt('error: could not release lockfile'));  
                 }  
             } else {  
                 push(@errors,&mt('error: could not obtain lockfile'));  
             }  
             if (keys(%courseonly)) {  
                 my $result = &Apache::lonnet::newput('tiny',\%courseonly,$cdom,$cnum);  
                 if ($result ne 'ok') {  
                     push(@errors,&mt('error: could not update course look-up of short URLs'));  
                 }  
             }  
         }  
     }  
     return ($numnew,\@errors);  
 }  
   
 sub shorten_symbs {  
     my ($cdom,$init,$su,$coursetiny,$tocreate,$newunique,$addcourse,$courseonly,$failed) = @_;  
     return unless ((ref($su)) && (ref($coursetiny) eq 'HASH') && (ref($tocreate) eq 'HASH') &&  
                    (ref($newunique) eq 'HASH') && (ref($addcourse) eq 'HASH') &&  
                    (ref($courseonly) eq 'HASH') && (ref($failed) eq 'HASH'));  
     my (%possibles,%collisions);  
     foreach my $key (keys(%{$tocreate})) {  
         my $num = String::CRC32::crc32($key);  
         my $tiny = $su->encode($num,$init);  
         if ($tiny) {  
             $possibles{$tiny} = $key;  
         }  
     }  
     if (!$init) {  
         $init = 1;  
     } else {  
         $init ++;  
     }  
     if (keys(%possibles)) {  
         my @posstiny = keys(%possibles);  
         my $configuname = &Apache::lonnet::get_domainconfiguser($cdom);  
         my %currtiny = &Apache::lonnet::get('tiny',\@posstiny,$cdom,$configuname);  
         if (keys(%currtiny)) {  
             foreach my $key (keys(%currtiny)) {  
                 next if ($currtiny{$key} eq '');  
                 if ($currtiny{$key} eq $possibles{$key}) {  
                     my ($tcnum,$tsymb) = split(/\&/,$currtiny{$key});  
                     unless (($coursetiny->{$tsymb} eq $key) || ($addcourse->{$tsymb} eq $key) || ($courseonly->{$tsymb} eq $key)) {  
                         $courseonly->{$tsymb} = $key;  
                     }  
                 } else {  
                     $collisions{$possibles{$key}} = 1;  
                 }  
                 delete($possibles{$key});  
             }  
         }  
         foreach my $key (keys(%possibles)) {  
             $newunique->{$key} = $possibles{$key};  
             my ($tcnum,$tsymb) = split(/\&/,$possibles{$key});  
             unless (($coursetiny->{$tsymb} eq $key) || ($addcourse->{$tsymb} eq $key) || ($courseonly->{$tsymb} eq $key)) {  
                 $addcourse->{$tsymb} = $key;  
             }  
         }  
     }  
     if (keys(%collisions)) {  
         if ($init <5) {  
             if (!$init) {  
                 $init = 1;  
             } else {  
                 $init ++;  
             }  
             $init = &shorten_symbs($cdom,$init,$su,$coursetiny,\%collisions,  
                                    $newunique,$addcourse,$courseonly,$failed);  
         } else {  
             foreach my $key (keys(%collisions)) {  
                 $failed->{$key} = 1;  
                 $failed->{$key} = 1;  
             }  
         }  
     }  
     return $init;  
 }  
   
 sub is_nonframeable {  
     my ($url,$absolute,$hostname,$ip,$nocache) = @_;  
     my ($remprotocol,$remhost) = ($url =~ m{^(https?)\://(([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,})}i);  
     return if (($remprotocol eq '') || ($remhost eq ''));  
   
     $remprotocol = lc($remprotocol);  
     $remhost = lc($remhost);  
     my $remport = 80;  
     if ($remprotocol eq 'https') {  
         $remport = 443;  
     }  
     my ($result,$cached) = &Apache::lonnet::is_cached_new('noiframe',$remhost.':'.$remport);  
     if ($cached) {  
         unless ($nocache) {  
             if ($result) {  
                 return 1;  
             } else {  
                 return 0;  
             }  
         }  
     }  
     my $uselink;  
     my $request = new HTTP::Request('HEAD',$url);  
     my $ua = LWP::UserAgent->new;  
     $ua->timeout(5);  
     my $response=$ua->request($request);  
     if ($response->is_success()) {  
         my $secpolicy = lc($response->header('content-security-policy'));  
         my $xframeop = lc($response->header('x-frame-options'));  
         $secpolicy =~ s/^\s+|\s+$//g;  
         $xframeop =~ s/^\s+|\s+$//g;  
         if (($secpolicy ne '') || ($xframeop ne '')) {  
             my $remotehost = $remprotocol.'://'.$remhost;  
             my ($origin,$protocol,$port);  
             if ($ENV{'SERVER_PORT'} =~/^\d+$/) {  
                 $port = $ENV{'SERVER_PORT'};  
             } else {  
                 $port = 80;  
             }  
             if ($absolute eq '') {  
                 $protocol = 'http:';  
                 if ($port == 443) {  
                     $protocol = 'https:';  
                 }  
                 $origin = $protocol.'//'.lc($hostname);  
             } else {  
                 $origin = lc($absolute);  
                 ($protocol,$hostname) = ($absolute =~ m{^(https?:)//([^/]+)$});  
             }  
             if (($secpolicy) && ($secpolicy =~ /\Qframe-ancestors\E([^;]*)(;|$)/)) {  
                 my $framepolicy = $1;  
                 $framepolicy =~ s/^\s+|\s+$//g;  
                 my @policies = split(/\s+/,$framepolicy);  
                 if (@policies) {  
                     if (grep(/^\Q'none'\E$/,@policies)) {  
                         $uselink = 1;  
                     } else {  
                         $uselink = 1;  
                         if ((grep(/^\Q*\E$/,@policies)) || (grep(/^\Q$protocol\E$/,@policies)) ||  
                                 (($origin ne '') && (grep(/^\Q$origin\E$/,@policies))) ||  
                                 (($ip ne '') && (grep(/^\Q$ip\E$/,@policies)))) {  
                             undef($uselink);  
                         }  
                         if ($uselink) {  
                             if (grep(/^\Q'self'\E$/,@policies)) {  
                                 if (($origin ne '') && ($remotehost eq $origin)) {  
                                     undef($uselink);  
                                 }  
                             }  
                         }  
                         if ($uselink) {  
                             my @possok;  
                             if ($ip ne '') {  
                                 push(@possok,$ip);  
                             }  
                             my $hoststr = '';  
                             foreach my $part (reverse(split(/\./,$hostname))) {  
                                 if ($hoststr eq '') {  
                                     $hoststr = $part;  
                                 } else {  
                                     $hoststr = "$part.$hoststr";  
                                 }  
                                 if ($hoststr eq $hostname) {  
                                     push(@possok,$hostname);  
                                 } else {  
                                     push(@possok,"*.$hoststr");  
                                 }  
                             }  
                             if (@possok) {  
                                 foreach my $poss (@possok) {  
                                     last if (!$uselink);  
                                     foreach my $policy (@policies) {  
                                         if ($policy =~ m{^(\Q$protocol\E//|)\Q$poss\E(\Q:$port\E|)$}) {  
                                             undef($uselink);  
                                             last;  
                                         }  
                                     }  
                                 }  
                             }  
                         }  
                     }  
                 }  
             } elsif ($xframeop ne '') {  
                 $uselink = 1;  
                 my @policies = split(/\s*,\s*/,$xframeop);  
                 if (@policies) {  
                     unless (grep(/^deny$/,@policies)) {  
                         if ($origin ne '') {  
                             if (grep(/^sameorigin$/,@policies)) {  
                                 if ($remotehost eq $origin) {  
                                     undef($uselink);  
                                 }  
                             }  
                             if ($uselink) {  
                                 foreach my $policy (@policies) {  
                                     if ($policy =~ /^allow-from\s*(.+)$/) {  
                                         my $allowfrom = $1;  
                                         if (($allowfrom ne '') && ($allowfrom eq $origin)) {  
                                             undef($uselink);  
                                             last;  
                                         }  
                                     }  
                                 }  
                             }  
                         }  
                     }  
                 }  
             }  
         }  
     }  
     if ($nocache) {  
         if ($cached) {  
             my $devalidate;  
             if ($uselink && !$result) {  
                 $devalidate = 1;  
             } elsif (!$uselink && $result) {  
                 $devalidate = 1;  
             }  
             if ($devalidate) {  
                 &Apache::lonnet::devalidate_cache_new('noiframe',$remhost.':'.$remport);  
             }  
         }  
     } else {  
         if ($uselink) {  
             $result = 1;  
         } else {  
             $result = 0;  
         }  
         &Apache::lonnet::do_cache_new('noiframe',$remhost.':'.$remport,$result,3600);  
     }  
     return $uselink;  
 }  
   
 sub page_menu {  
     my ($menucolls,$menunum) = @_;  
     my %menu;  
     foreach my $item (split(/;/,$menucolls)) {  
         my ($num,$value) = split(/\%/,$item);  
         if ($num eq $menunum) {  
             my @entries = split(/\&/,$value);  
             foreach my $entry (@entries) {  
                 my ($name,$fields) = split(/=/,$entry);  
                 if (($name eq 'top') || ($name eq 'inline') || ($name eq 'foot') || ($name eq 'main')) {  
                     $menu{$name} = $fields;  
                 } else {  
                     my @shown;  
                     if ($fields =~ /,/) {  
                         @shown = split(/,/,$fields);  
                     } else {  
                         @shown = ($fields);  
                     }  
                     if (@shown) {  
                         foreach my $field (@shown) {  
                             next if ($field eq '');  
                             $menu{$field} = 1;  
                         }  
                     }  
                 }  
             }  
         }  
     }  
     return %menu;  
 }  
   
 1;  1;
 __END__;  __END__;
   

Removed from v.1.1075.2.161.2.14  
changed lines
  Added in v.1.1235


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