Diff for /loncom/interface/loncommon.pm between versions 1.1228 and 1.1257

version 1.1228, 2015/08/16 20:45:41 version 1.1257, 2016/10/12 14:54:08
Line 72  use Apache::lonuserstate(); Line 72  use Apache::lonuserstate();
 use Apache::courseclassifier();  use Apache::courseclassifier();
 use LONCAPA qw(:DEFAULT :match);  use LONCAPA qw(:DEFAULT :match);
 use DateTime::TimeZone;  use DateTime::TimeZone;
 use DateTime::Locale::Catalog;  use DateTime::Locale;
 use Encode();  use Encode();
 use Text::Aspell;  use Text::Aspell;
 use Authen::Captcha;  use Authen::Captcha;
 use Captcha::reCAPTCHA;  use Captcha::reCAPTCHA;
   use JSON::DWIW;
   use LWP::UserAgent;
 use Crypt::DES;  use Crypt::DES;
 use DynaLoader; # for Crypt::DES version  use DynaLoader; # for Crypt::DES version
 use MIME::Lite;  use MIME::Lite;
Line 588  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+'&crscode='+document.forms[formid].crscode.value;              url += '&cloner='+ownername+':'+ownerdom;
               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 876  sub selectcourse_link { Line 881  sub selectcourse_link {
    my $linktext = &mt('Select Course');     my $linktext = &mt('Select Course');
    if ($selecttype eq 'Community') {     if ($selecttype eq 'Community') {
        $linktext = &mt('Select Community');         $linktext = &mt('Select Community');
      } elsif ($selecttype eq 'Placement') {
          $linktext = &mt('Select Placement Test'); 
    } elsif ($selecttype eq 'Course/Community') {     } elsif ($selecttype eq 'Course/Community') {
        $linktext = &mt('Select Course/Community');         $linktext = &mt('Select Course/Community');
        $type = '';         $type = '';
Line 936  ENDSCRT Line 943  ENDSCRT
 }  }
   
 sub select_timezone {  sub select_timezone {
    my ($name,$selected,$onchange,$includeempty)=@_;     my ($name,$selected,$onchange,$includeempty,$disabled)=@_;
    my $output='<select name="'.$name.'" '.$onchange.'>'."\n";     my $output='<select name="'.$name.'" '.$onchange.$disabled.'>'."\n";
    if ($includeempty) {     if ($includeempty) {
        $output .= '<option value=""';         $output .= '<option value=""';
        if (($selected eq '') || ($selected eq 'local')) {         if (($selected eq '') || ($selected eq 'local')) {
Line 958  sub select_timezone { Line 965  sub select_timezone {
 }  }
   
 sub select_datelocale {  sub select_datelocale {
     my ($name,$selected,$onchange,$includeempty)=@_;      my ($name,$selected,$onchange,$includeempty,$disabled)=@_;
     my $output='<select name="'.$name.'" '.$onchange.'>'."\n";      my $output='<select name="'.$name.'" '.$onchange.$disabled.'>'."\n";
     if ($includeempty) {      if ($includeempty) {
         $output .= '<option value=""';          $output .= '<option value=""';
         if ($selected eq '') {          if ($selected eq '') {
Line 967  sub select_datelocale { Line 974  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::Catalog::Locales;      my @locales = DateTime::Locale->ids();
     foreach my $locale (@locales) {      foreach my $id (@locales) {
         if (ref($locale) eq 'HASH') {          if ($id ne '') {
             my $id = $locale->{'id'};              my ($en_terr,$native_terr);
             if ($id ne '') {              my $loc = DateTime::Locale->load($id);
                 my $en_terr = $locale->{'en_territory'};              if (ref($loc)) {
                 my $native_terr = $locale->{'native_territory'};                  $en_terr = $loc->name();
                 my @languages = &Apache::lonlocal::preferred_languages();                  $native_terr = $loc->native_name();
                 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 990  sub select_datelocale { Line 998  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);
             }              } 
         }          }
     }      }
     foreach my $item (sort(@possibles)) {      foreach my $item (sort(@possibles)) {
Line 1010  sub select_datelocale { Line 1018  sub select_datelocale {
 }  }
   
 sub select_language {  sub select_language {
     my ($name,$selected,$includeempty) = @_;      my ($name,$selected,$includeempty,$noedit) = @_;
     my %langchoices;      my %langchoices;
     if ($includeempty) {      if ($includeempty) {
         %langchoices = ('' => 'No language preference');          %langchoices = ('' => 'No language preference');
Line 1022  sub select_language { Line 1030  sub select_language {
         }          }
     }      }
     %langchoices = &Apache::lonlocal::texthash(%langchoices);      %langchoices = &Apache::lonlocal::texthash(%langchoices);
     return &select_form($selected,$name,\%langchoices);      return &select_form($selected,$name,\%langchoices,undef,$noedit);
 }  }
   
 =pod  =pod
Line 1086  linked_select_forms takes the following Line 1094  linked_select_forms takes the following
 =item * $onchangesecond, additional javascript call to execute for an onchange  =item * $onchangesecond, additional javascript call to execute for an onchange
         event for the second <select> tag          event for the second <select> tag
   
   =item * $suffix, to differentiate separate uses of select2data javascript
           objects in a page.
   
 =back   =back 
   
 Below is an example of such a hash.  Only the 'text', 'default', and   Below is an example of such a hash.  Only the 'text', 'default', and 
Line 1140  sub linked_select_forms { Line 1151  sub linked_select_forms {
         $hashref,          $hashref,
         $menuorder,          $menuorder,
         $onchangefirst,          $onchangefirst,
         $onchangesecond          $onchangesecond,
           $suffix
         ) = @_;          ) = @_;
     my $second = "document.$formname.$secondselectname";      my $second = "document.$formname.$secondselectname";
     my $first = "document.$formname.$firstselectname";      my $first = "document.$formname.$firstselectname";
Line 1148  sub linked_select_forms { Line 1160  sub linked_select_forms {
     my $result = '';      my $result = '';
     $result.='<script type="text/javascript" language="JavaScript">'."\n";      $result.='<script type="text/javascript" language="JavaScript">'."\n";
     $result.="// <![CDATA[\n";      $result.="// <![CDATA[\n";
     $result.="var select2data = new Object();\n";      $result.="var select2data${suffix} = new Object();\n";
     $" = '","';      $" = '","';
     my $debug = '';      my $debug = '';
     foreach my $s1 (sort(keys(%$hashref))) {      foreach my $s1 (sort(keys(%$hashref))) {
         $result.="select2data.d_$s1 = new Object();\n";                  $result.="select2data${suffix}['d_$s1'] = new Object();\n";        
         $result.="select2data.d_$s1.def = new String('".          $result.="select2data${suffix}['d_$s1'].def = new String('".
             $hashref->{$s1}->{'default'}."');\n";              $hashref->{$s1}->{'default'}."');\n";
         $result.="select2data.d_$s1.values = new Array(";          $result.="select2data${suffix}['d_$s1'].values = new Array(";
         my @s2values = sort(keys( %{ $hashref->{$s1}->{'select2'} } ));          my @s2values = sort(keys( %{ $hashref->{$s1}->{'select2'} } ));
         if (ref($hashref->{$s1}->{'order'}) eq 'ARRAY') {          if (ref($hashref->{$s1}->{'order'}) eq 'ARRAY') {
             @s2values = @{$hashref->{$s1}->{'order'}};              @s2values = @{$hashref->{$s1}->{'order'}};
         }          }
         $result.="\"@s2values\");\n";          $result.="\"@s2values\");\n";
         $result.="select2data.d_$s1.texts = new Array(";                  $result.="select2data${suffix}['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};
Line 1171  sub linked_select_forms { Line 1183  sub linked_select_forms {
     $"=' ';      $"=' ';
     $result.= <<"END";      $result.= <<"END";
   
 function select1_changed() {  function select1${suffix}_changed() {
     // Determine new choice      // Determine new choice
     var newvalue = "d_" + $first.value;      var newvalue = "d_" + $first.options[$first.selectedIndex].value;
     // update select2      // update select2
     var values     = select2data[newvalue].values;      var values     = select2data${suffix}[newvalue].values;
     var texts      = select2data[newvalue].texts;      var texts      = select2data${suffix}[newvalue].texts;
     var select2def = select2data[newvalue].def;      var select2def = select2data${suffix}[newvalue].def;
     var i;      var i;
     // out with the old      // out with the old
     for (i = 0; i < $second.options.length; i++) {      $second.options.length = 0;
         $second.options[i] = null;      // in with the new
     }  
     // in with the nuclear  
     for (i=0;i<values.length; i++) {      for (i=0;i<values.length; i++) {
         $second.options[i] = new Option(values[i]);          $second.options[i] = new Option(values[i]);
         $second.options[i].value = values[i];          $second.options[i].value = values[i];
Line 1197  function select1_changed() { Line 1207  function select1_changed() {
 </script>  </script>
 END  END
     # output the initial values for the selection lists      # output the initial values for the selection lists
     $result .= "<select size=\"1\" name=\"$firstselectname\" onchange=\"select1_changed();$onchangefirst\">\n";      $result .= "<select size=\"1\" name=\"$firstselectname\" onchange=\"select1${suffix}_changed();$onchangefirst\">\n";
     my @order = sort(keys(%{$hashref}));      my @order = sort(keys(%{$hashref}));
     if (ref($menuorder) eq 'ARRAY') {      if (ref($menuorder) eq 'ARRAY') {
         @order = @{$menuorder};          @order = @{$menuorder};
Line 1765  RESIZE Line 1775  RESIZE
 }  }
   
 sub colorfuleditor_js {  sub colorfuleditor_js {
       my $browse_or_search;
       my $respath;
       my ($cnum,$cdom) = &crsauthor_url();
       if ($cnum) {
           $respath = "/res/$cdom/$cnum/";
           my %js_lt = &Apache::lonlocal::texthash(
               sunm => 'Sub-directory name',
               save => 'Save page to make this permanent',
           );
           &js_escape(\%js_lt);
           $browse_or_search = <<"END";
   
       function toggleChooser(form,element,titleid,only,search) {
           var disp = 'none';
           if (document.getElementById('chooser_'+element)) {
               var curr = document.getElementById('chooser_'+element).style.display;
               if (curr == 'none') {
                   disp='inline';
                   if (form.elements['chooser_'+element].length) {
                       for (var i=0; i<form.elements['chooser_'+element].length; i++) {
                           form.elements['chooser_'+element][i].checked = false;
                       }
                   }
                   toggleResImport(form,element);
               }
               document.getElementById('chooser_'+element).style.display = disp;
           }
       }
   
       function toggleCrsFile(form,element,numdirs) {
           if (document.getElementById('chooser_'+element+'_crsres')) {
               var curr = document.getElementById('chooser_'+element+'_crsres').style.display;
               if (curr == 'none') {
                   if (numdirs) {
                       form.elements['coursepath_'+element].selectedIndex = 0;
                       if (numdirs > 1) {
                           window['select1'+element+'_changed']();
                       }
                   }
               } 
               document.getElementById('chooser_'+element+'_crsres').style.display = 'block';
               
           }
           if (document.getElementById('chooser_'+element+'_upload')) {
               document.getElementById('chooser_'+element+'_upload').style.display = 'none';
               if (document.getElementById('uploadcrsres_'+element)) {
                   document.getElementById('uploadcrsres_'+element).value = '';
               }
           }
           return;
       }
   
       function toggleCrsUpload(form,element,numcrsdirs) {
           if (document.getElementById('chooser_'+element+'_crsres')) {
               document.getElementById('chooser_'+element+'_crsres').style.display = 'none';
           }
           if (document.getElementById('chooser_'+element+'_upload')) {
               var curr = document.getElementById('chooser_'+element+'_upload').style.display;
               if (curr == 'none') {
                   if (numcrsdirs) {
                      form.elements['crsauthorpath_'+element].selectedIndex = 0;
                      form.elements['newsubdir_'+element][0].checked = true;
                      toggleNewsubdir(form,element);
                   }
               }
               document.getElementById('chooser_'+element+'_upload').style.display = 'block';
           }
           return;
       }
   
       function toggleResImport(form,element) {
           var choices = new Array('crsres','upload');
           for (var i=0; i<choices.length; i++) {
               if (document.getElementById('chooser_'+element+'_'+choices[i])) {
                   document.getElementById('chooser_'+element+'_'+choices[i]).style.display = 'none';
               }
           }
       }
   
       function toggleNewsubdir(form,element) {
           var newsub = form.elements['newsubdir_'+element];
           if (newsub) {
               if (newsub.length) {
                   for (var j=0; j<newsub.length; j++) {
                       if (newsub[j].checked) {
                           if (document.getElementById('newsubdirname_'+element)) {
                               if (newsub[j].value == '1') {
                                   document.getElementById('newsubdirname_'+element).type = "text";
                                   if (document.getElementById('newsubdir_'+element)) {
                                       document.getElementById('newsubdir_'+element).innerHTML = '<br />$js_lt{sunm}';
                                   }
                               } else {
                                   document.getElementById('newsubdirname_'+element).type = "hidden";
                                   document.getElementById('newsubdirname_'+element).value = "";
                                   document.getElementById('newsubdir_'+element).innerHTML = "";
                               }
                           }
                           break; 
                       }
                   }
               }
           }
       }
   
       function updateCrsFile(form,element) {
           var directory = form.elements['coursepath_'+element];
           var filename = form.elements['coursefile_'+element];
           var path = directory.options[directory.selectedIndex].value;
           var file = filename.options[filename.selectedIndex].value;
           form.elements[element].value = '$respath';
           if (path == '/') {
               form.elements[element].value += file;
           } else {
               form.elements[element].value += path+'/'+file;
           }
           unClean();
           if (document.getElementById('previewimg_'+element)) {
               document.getElementById('previewimg_'+element).src = form.elements[element].value;
               var newsrc = document.getElementById('previewimg_'+element).src; 
           }
           if (document.getElementById('showimg_'+element)) {
               document.getElementById('showimg_'+element).innerHTML = '($js_lt{save})';
           }
           toggleChooser(form,element);
           return;
       }
   
       function uploadDone(suffix,name) {
           if (name) {
       document.forms["lonhomework"].elements[suffix].value = name;
               unClean();
               toggleChooser(document.forms["lonhomework"],suffix);
           }
       }
   
   \$(document).ready(function(){
   
       \$(document).delegate('form :submit', 'click', function( event ) {
           if ( \$( this ).hasClass( "LC_uploadcrsres" ) ) {
               var buttonId = this.id;
               var suffix = buttonId.toString();
               suffix = suffix.replace(/^crsupload_/,'');
               event.preventDefault();
               document.lonhomework.target = 'crsupload_target_'+suffix;
               document.lonhomework.action = '/adm/coursepub?LC_uploadcrsres='+suffix;
               \$(this.form).submit();
               document.lonhomework.target = '';
               if (document.getElementById('crsuploadto_'+suffix)) {
                   document.lonhomework.action = document.getElementById('crsuploadto_'+suffix).value;
               }
               return false;
           }
       });
   });
   END
       }
     return <<"COLORFULEDIT"      return <<"COLORFULEDIT"
 <script type="text/javascript">  <script type="text/javascript">
 // <![CDATA[>  // <![CDATA[>
Line 1947  sub colorfuleditor_js { Line 2113  sub colorfuleditor_js {
         }          }
     }      }
   
   $browse_or_search
   
 // ]]>  // ]]>
 </script>  </script>
Line 1999  sub insert_folding_button { Line 2165  sub insert_folding_button {
             value=\"".&mt('Hide')."\" onclick=\"fold_box('$curDepth','$lastresource')\">";              value=\"".&mt('Hide')."\" onclick=\"fold_box('$curDepth','$lastresource')\">";
 }  }
   
   sub crsauthor_url {
       my ($url) = @_;
       if ($url eq '') {
           $url = $ENV{'REQUEST_URI'};
       }
       my ($cnum,$cdom);
       if ($env{'request.course.id'}) {
           my ($audom,$auname) = ($url =~ m{^/priv/($match_domain)/($match_name)/});
           if ($audom ne '' && $auname ne '') {
               if (($env{'course.'.$env{'request.course.id'}.'.num'} eq $auname) &&
                   ($env{'course.'.$env{'request.course.id'}.'.domain'} eq $audom)) {
                   $cnum = $auname;
                   $cdom = $audom;
               }
           }
       }
       return ($cnum,$cdom);
   }
   
   sub import_crsauthor_form {
       my ($form,$firstselectname,$secondselectname,$onchangefirst,$only,$suffix) = @_;
       return (0) unless ($env{'request.course.id'});
       my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
       my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
       my $crshome = $env{'course.'.$env{'request.course.id'}.'.home'};
       return (0) unless (($cnum ne '') && ($cdom ne ''));
       my $londocroot = $Apache::lonnet::perlvar{'lonDocRoot'};
       my @ids=&Apache::lonnet::current_machine_ids();
       my ($output,$is_home,$relpath,%subdirs,%files,%selimport_menus);
       
       if (grep(/^\Q$crshome\E$/,@ids)) {
           $is_home = 1;
       }
       $relpath = "/priv/$cdom/$cnum";
       &Apache::lonnet::recursedirs($is_home,'priv',$londocroot,$relpath,'',\%subdirs,\%files);
       my %lt = &Apache::lonlocal::texthash (
           fnam => 'Filename',
           dire => 'Directory',
       );
       my $numdirs = scalar(keys(%files));
       my (%possexts,$singledir,@singledirfiles);
       if ($only) {
           map { $possexts{$_} = 1; } split(/\s*,\s*/,$only);
       }
       my (%nonemptydirs,$possdirs);
       if ($numdirs > 1) {
           my @order;
           foreach my $key (sort { lc($a) cmp lc($b) } (keys(%files))) {
               if (ref($files{$key}) eq 'HASH') {
                   my $shown = $key;
                   if ($key eq '') {
                       $shown = '/';
                   }
                   my @ordered = ();
                   foreach my $file (sort { lc($a) cmp lc($b) } (keys(%{$files{$key}}))) {
                       if ($only) {
                           my ($ext) = ($file =~ /\.([^.]+)$/);
                           unless ($possexts{lc($ext)}) {
                               next;
                           }
                       }
                       $selimport_menus{$key}->{'select2'}->{$file} = $file;
                       push(@ordered,$file);
                   }
                   if (@ordered) {
                       push(@order,$key);
                       $nonemptydirs{$key} = 1;
                       $selimport_menus{$key}->{'text'} = $shown;
                       $selimport_menus{$key}->{'default'} = '';
                       $selimport_menus{$key}->{'select2'}->{''} = '';
                       $selimport_menus{$key}->{'order'} = \@ordered;
                   }
               }
           }
           $possdirs = scalar(keys(%nonemptydirs));
           if ($possdirs > 1) {
               my @order = sort { lc($a) cmp lc($b) } (keys(%nonemptydirs));
               $output = $lt{'dire'}.
                         &linked_select_forms($form,'<br />'.
                                              $lt{'fnam'},'',
                                              $firstselectname,$secondselectname,
                                              \%selimport_menus,\@order,
                                              $onchangefirst,'',$suffix).'<br />';
           } elsif ($possdirs == 1) {
               $singledir = (keys(%nonemptydirs))[0];
               if (ref($selimport_menus{$singledir}->{'order'}) eq 'ARRAY') {
                   @singledirfiles = @{$selimport_menus{$singledir}->{'order'}};
               }
               delete($selimport_menus{$singledir});
           }
       } elsif ($numdirs == 1) {
           $singledir = (keys(%files))[0];
           foreach my $file (sort { lc($a) cmp lc($b) } (keys(%{$files{$singledir}}))) {
               if ($only) {
                   my ($ext) = ($file =~ /\.([^.]+)$/);
                   unless ($possexts{lc($ext)}) {
                       next;
                   }
               }
               push(@singledirfiles,$file);
           }
           if (@singledirfiles) {
               $possdirs == 1;
           }
       }
       if (($possdirs == 1) && (@singledirfiles)) {
           my $showdir = $singledir;
           if ($singledir eq '') {
               $showdir = '/';
           }
           $output = $lt{'dire'}.
                     '<select name="'.$firstselectname.'">'.
                     '<option value="'.$singledir.'">'.$showdir.'</option>'."\n".
                     '</select><br />'.
                     $lt{'fnam'}.'<select name="'.$secondselectname.'">'."\n".
                     '<option value="" selected="selected">'.$lt{'se'}.'</option>'."\n";
           foreach my $file (@singledirfiles) {
               $output .= '<option value="'.$file.'">'.$file.'</option>'."\n";
           }
           $output .= '</select><br />'."\n";
       }
       return ($possdirs,$output);
   }
   
 =pod  =pod
   
 =head1 Excel and CSV file utility routines  =head1 Excel and CSV file utility routines
Line 2258  sub multiple_select_form { Line 2548  sub multiple_select_form {
   
 =pod  =pod
   
 =item * &select_form($defdom,$name,$hashref,$onchange)  =item * &select_form($defdom,$name,$hashref,$onchange,$readonly)
   
 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 2449  sub select_level_form { Line 2742  sub select_level_form {
   
 =pod  =pod
   
 =item * &select_dom_form($defdom,$name,$includeempty,$showdomdesc,$onchange,$incdoms,$excdoms)  =item * &select_dom_form($defdom,$name,$includeempty,$showdomdesc,$onchange,$incdoms,$excdoms,$disabled)
   
 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 2466  The optional $incdoms is a reference to Line 2759  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) = @_;      my ($defdom,$name,$includeempty,$showdomdesc,$onchange,$incdoms,$excdoms,$disabled) = @_;
     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 2484  sub select_dom_form { Line 2782  sub select_dom_form {
     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>\n";      my $selectdomain = "<select name=\"$name\" size=\"1\"$onchange$disabled>\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 3864  category Line 4162  category
   
 sub filecategorytypes {  sub filecategorytypes {
     my ($cat) = @_;      my ($cat) = @_;
     return @{$category_extensions{lc($cat)}};      if (ref($category_extensions{lc($cat)}) eq 'ARRAY') { 
           return @{$category_extensions{lc($cat)}};
       } else {
           return ();
       }
 }  }
   
 =pod  =pod
Line 4959  sub blocking_status { Line 5261  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 the user is trying to look at  # $uname and $udom decide whose portfolio the user is trying to look at
     if ($activity eq 'port') {      if (($activity eq 'port') || ($activity eq 'passwd')) {
         $querystring .= "&amp;udom=$udom"      if $udom;          $querystring .= "&amp;udom=$udom"      if ($udom =~ /^$match_domain$/); 
         $querystring .= "&amp;uname=$uname"    if $uname;          $querystring .= "&amp;uname=$uname"    if ($uname =~ /^$match_username$/);
     } elsif ($activity eq 'docs') {      } elsif ($activity eq 'docs') {
         $querystring .= '&amp;url='.&HTML::Entities::encode($url,'&"');          $querystring .= '&amp;url='.&HTML::Entities::encode($url,'&"');
     }      }
Line 4986  END_MYBLOCK Line 5288  END_MYBLOCK
         $class = '';          $class = '';
     } elsif ($activity eq 'printout') {      } elsif ($activity eq 'printout') {
         $text = &mt('Printing Blocked');          $text = &mt('Printing Blocked');
       } elsif ($activity eq 'passwd') {
           $text = &mt('Password Changing Blocked');
     }      }
     $output .= <<"END_BLOCK";      $output .= <<"END_BLOCK";
 <div class='$class'>  <div class='$class'>
Line 5010  sub check_ip_acc { Line 5314  sub check_ip_acc {
         return 1;          return 1;
     }      }
     my $allowed;      my $allowed;
     my $ip=$env{'request.host'} || $ENV{'REMOTE_ADDR'} || $clientip;      my $ip=$ENV{'REMOTE_ADDR'} || $clientip || $env{'request.host'};
   
     my $name;      my $name;
     my %access = (      my %access = (
Line 5414  sub CSTR_pageheader { Line 5718  sub CSTR_pageheader {
         $lastitem = $thisdisfn;          $lastitem = $thisdisfn;
     }      }
   
       my ($crsauthor,$title);
       if (($env{'request.course.id'}) &&
           ($env{'course.'.$env{'request.course.id'}.'.num'} eq $uname) &&
           ($env{'course.'.$env{'request.course.id'}.'.domain'} eq $udom)) {
           $crsauthor = 1;
           $title = &mt('Course Authoring Space');
       } else {
           $title = &mt('Authoring Space');
       }
   
     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>'.$title.'</b> '
         .'<form name="dirs" method="post" action="'.$formaction          .'<form name="dirs" method="post" action="'.$formaction
         .'" target="_top">' #FIXME lonpubdir: target="_parent"          .'" target="_top">' #FIXME lonpubdir: target="_parent"
         .&Apache::lonhtmlcommon::crumbs($uname.'/'.$parentpath,'_top','/priv/'.$udom,undef,undef);          .&Apache::lonhtmlcommon::crumbs($uname.'/'.$parentpath,'_top','/priv/'.$udom,undef,undef);
Line 5428  sub CSTR_pageheader { Line 5742  sub CSTR_pageheader {
             .$lastitem              .$lastitem
             .'</span>';              .'</span>';
     }      }
     $output .=  
          '<br />'      if ($crsauthor) {
         #FIXME lonpubdir: &Apache::lonhtmlcommon::crumbs($uname.$thisdisfn.'/','_top','/priv','','+1',1)."</b></tt><br />"          $output .= '</form>'.&Apache::lonmenu::constspaceform();
         .&Apache::lonhtmlcommon::select_recent('construct','recent','this.form.action=this.form.recent.value;this.form.submit()')      } else {
         .'</form>'          $output .=
         .&Apache::lonmenu::constspaceform()               '<br />'
         .'</div>';              #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()')
               .'</form>'
               .&Apache::lonmenu::constspaceform();
       }
       $output .= '</div>';
   
     return $output;      return $output;
 }  }
Line 5478  Inputs: Line 5797  Inputs:
   
 =item * $args, optional argument valid values are  =item * $args, optional argument valid values are
             no_auto_mt_title -> prevents &mt()ing the title arg              no_auto_mt_title -> prevents &mt()ing the title arg
             inherit_jsmath -> when creating popup window in a page,  
                               should it have jsmath forced on by the  
                               current page  
   
 =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
Line 5533  sub bodytag { Line 5849  sub bodytag {
     if ($env{'request.course.id'}) {      if ($env{'request.course.id'}) {
         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+)$}) {
               $role = &mt('Helpdesk[_1]','&nbsp;'.$2); 
           } else {
               $role = (split(/\//,$role,4))[-1]; 
         }          }
         if ($env{'request.course.sec'}) {          if ($env{'request.course.sec'}) {
             $role .= ('&nbsp;'x2).'-&nbsp;'.&mt('section:').'&nbsp;'.$env{'request.course.sec'};              $role .= ('&nbsp;'x2).'-&nbsp;'.&mt('section:').'&nbsp;'.$env{'request.course.sec'};
Line 5548  sub bodytag { Line 5868  sub bodytag {
   
 # construct main body tag  # construct main body tag
     my $bodytag = "<body $extra_body_attr>".      my $bodytag = "<body $extra_body_attr>".
  &Apache::lontexconvert::init_math_support($args->{'inherit_jsmath'});   &Apache::lontexconvert::init_math_support();
   
     &get_unprocessed_cgi($ENV{'QUERY_STRING'}, ['inhibitmenu']);      &get_unprocessed_cgi($ENV{'QUERY_STRING'}, ['inhibitmenu']);
   
Line 5572  sub bodytag { Line 5892  sub bodytag {
         $dc_info =~ s/\s+$//;          $dc_info =~ s/\s+$//;
     }      }
   
     $role = '<span class="LC_nobreak">('.$role.')</span>' if $role;      my $crstype;
       if ($env{'request.course.id'}) {
           $crstype = $env{'course.'.$env{'request.course.id'}.'.type'};
       } elsif ($args->{'crstype'}) {
           $crstype = $args->{'crstype'};
       }
       if (($crstype eq 'Placement') && (!$env{'request.role.adv'})) {
           undef($role);
       } else {
           $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; }
   
Line 5583  sub bodytag { Line 5913  sub bodytag {
         $bodytag .= Apache::lonhtmlcommon::scripttag(          $bodytag .= Apache::lonhtmlcommon::scripttag(
             Apache::lonmenu::utilityfunctions($httphost), 'start');              Apache::lonmenu::utilityfunctions($httphost), 'start');
   
         my ($left,$right) = Apache::lonmenu::primary_menu();          my ($left,$right) = Apache::lonmenu::primary_menu($crstype);
   
         if ($env{'request.noversionuri'} =~ m{^/res/adm/pages/}) {          if ($env{'request.noversionuri'} =~ m{^/res/adm/pages/}) {
              if ($dc_info) {               if ($dc_info) {
Line 5701  sub endbodytag { Line 6031  sub endbodytag {
     unless ((ref($args) eq 'HASH') && ($args->{'notbody'})) {      unless ((ref($args) eq 'HASH') && ($args->{'notbody'})) {
         $endbodytag='</body>';          $endbodytag='</body>';
     }      }
     $endbodytag=&Apache::lontexconvert::jsMath_process()."\n".$endbodytag;  
     if ( exists( $env{'internal.head.redirect'} ) ) {      if ( exists( $env{'internal.head.redirect'} ) ) {
         if (!(ref($args) eq 'HASH' && $args->{'noredirectlink'})) {          if (!(ref($args) eq 'HASH' && $args->{'noredirectlink'})) {
     $endbodytag=      $endbodytag=
Line 5876  div.LC_confirm_box .LC_success img { Line 6205  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 5981  ul.LC_breadcrumb_tools_outerlist li { Line 6321  ul.LC_breadcrumb_tools_outerlist li {
     float: right;      float: right;
 }  }
   
   .LC_placement_prog {
       padding-right: 20px;
       font-weight: bold;
       font-size: 90%;
   }
   
 table#LC_title_bar td {  table#LC_title_bar td {
   background: $tabbg;    background: $tabbg;
 }  }
Line 5997  table#LC_menubuttons img { Line 6343  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 7648  ul.LC_funclist li { Line 7998  ul.LC_funclist li {
 }  }
   
 /*  /*
     styles used for response display
   */
   div.LC_radiofoil, div.LC_rankfoil {
     margin: .5em 0em .5em 0em;
   }
   table.LC_itemgroup {
     margin-top: 1em;
   }
   
   /*
   styles used by TTH when "Default set of options to pass to tth/m    styles used by TTH when "Default set of options to pass to tth/m
   when converting TeX" in course settings has been set    when converting TeX" in course settings has been set
   
Line 7668  span.roman {font-family: serif; font-sty Line 8028  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;}
   
   /*
     sections with roles, for content only
   */
   section[class^="role-"] {
     padding-left: 10px;
     padding-right: 5px;
     margin-top: 8px;
     margin-bottom: 8px;
     border: 1px solid #2A4;
     border-radius: 5px;
     box-shadow: 0px 1px 1px #BBB;
   }
   section[class^="role-"]>h1 {
     position: relative;
     margin: 0px;
     padding-top: 10px;
     padding-left: 40px;
   }
   section[class^="role-"]>h1:before {
     position: absolute;
     left: -5px;
     top: 5px;
   }
   section.role-activity>h1:before {
     content:url('/adm/daxe/images/section_icons/activity.png');
   }
   section.role-advice>h1:before {
     content:url('/adm/daxe/images/section_icons/advice.png');
   }
   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 7849  OFFLOAD Line 8290  OFFLOAD
     $result .= '>'       $result .= '>' 
         .$inhibitprint          .$inhibitprint
  .$head_extra;   .$head_extra;
     if ($env{'browser.mobile'}) {      my $clientmobile;
       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" />';
Line 8031  $args - additional optional args support Line 8478  $args - additional optional args support
                                     head -> skip the <html><head> generation                                      head -> skip the <html><head> generation
                                     body -> skip all <body> generation                                      body -> skip all <body> generation
              no_auto_mt_title -> prevent &mt()ing the title arg               no_auto_mt_title -> prevent &mt()ing the title arg
              inherit_jsmath -> when creating popup window in a page,  
                                     should it have jsmath forced on by the  
                                     current page  
              bread_crumbs ->             Array containing breadcrumbs               bread_crumbs ->             Array containing breadcrumbs
              bread_crumbs_component ->  if exists show it as headline else show only the breadcrumbs               bread_crumbs_component ->  if exists show it as headline else show only the breadcrumbs
              group          -> includes the current group, if page is for a                group          -> includes the current group, if page is for a 
Line 8105  sub start_page { Line 8549  sub start_page {
  #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'});   $result .= &Apache::lonhtmlcommon::breadcrumbs($args->{'bread_crumbs_component'});
  }else{   } elsif ($args->{'crstype'} eq 'Placement') {
    $result .= &Apache::lonhtmlcommon::breadcrumbs('','','','','','','','','',
                                                                          $args->{'crstype'});
                   } else {
  $result .= &Apache::lonhtmlcommon::breadcrumbs();   $result .= &Apache::lonhtmlcommon::breadcrumbs();
  }   }
     }      }
Line 9222  Incoming parameters: Line 9669  Incoming parameters:
 2. user's domain  2. user's domain
 3. quota name - portfolio, author, or course  3. quota name - portfolio, author, or course
    (if no quota name provided, defaults to portfolio).     (if no quota name provided, defaults to portfolio).
 4. crstype - official, unofficial, textbook or community, if quota name is  4. crstype - official, unofficial, textbook, placement or community, 
    course     if quota name is course
   
 Returns:  Returns:
 1. Disk quota (in MB) assigned to student.  1. Disk quota (in MB) assigned to student.
Line 9297  sub get_user_quota { Line 9744  sub get_user_quota {
             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') ||
                       ($crstype eq 'placement')) { 
                     $defquota = $domdefs{$crstype.'quota'};                      $defquota = $domdefs{$crstype.'quota'};
                 }                  }
                 if ($defquota eq '') {                  if ($defquota eq '') {
Line 9445  Inputs: 7 Line 9893  Inputs: 7
 4. filename of file for which action is being requested  4. filename of file for which action is being requested
 5. filesize (kB) of file  5. filesize (kB) of file
 6. action being taken: copy or upload.  6. action being taken: copy or upload.
 7. quotatype (in course context -- official, unofficial, community or textbook).  7. quotatype (in course context -- official, unofficial, textbook, placement or community).
   
 Returns: 1 scalar: HTML to display containing warning if quota would be exceeded,  Returns: 1 scalar: HTML to display containing warning if quota would be exceeded,
          otherwise return null.           otherwise return null.
Line 9521  sub get_secgrprole_info { Line 9969  sub get_secgrprole_info {
 }  }
   
 sub user_picker {  sub user_picker {
     my ($dom,$srch,$forcenewuser,$caller,$cancreate,$usertype,$context) = @_;      my ($dom,$srch,$forcenewuser,$caller,$cancreate,$usertype,$context,$fixeddom) = @_;
     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 9569  sub user_picker { Line 10033  sub user_picker {
                                        );                                         );
     &html_escape(\%html_lt);      &html_escape(\%html_lt);
     &js_escape(\%js_lt);      &js_escape(\%js_lt);
     my $domform = &select_dom_form($currdom,'srchdomain',1,1);      my $domform;
       if ($fixeddom) {
           $domform = &select_dom_form($currdom,'srchdomain',1,1,undef,[$currdom]);
       } else {
           $domform = &select_dom_form($currdom,'srchdomain',1,1);
       }
     my $srchinsel = ' <select name="srchin">';      my $srchinsel = ' <select name="srchin">';
   
     my @srchins = ('crs','dom','alc','instd');      my @srchins = ('crs','dom','alc','instd');
Line 9763  END_BLOCK Line 10232  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;      return ($output,1);
 }  }
   
 sub user_rule_check {  sub user_rule_check {
Line 10189  reservable_now - ref to hash of student_ Line 10658  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 10199  future_reservable - ref to hash of stude Line 10670  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 10207  future_reservable - ref to hash of stude Line 10680  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 10253  sub get_future_slots { Line 10748  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 10261  sub get_future_slots { Line 10760  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 10425  sub get_env_multiple { Line 10926  sub get_env_multiple {
     return(@values);      return(@values);
 }  }
   
   # Looks at given dependencies, and returns something depending on the context.
   # For coursedocs paste, returns (undef, $counter, $numpathchg, \%existing).
   # For syllabus rewrites, returns (undef, $counter, $numpathchg, \%existing, \%mapping).
   # For all other contexts, returns ($output, $counter, $numpathchg).
   # $output: string with the HTML output. Can contain missing dependencies with an upload form, existing dependencies, and dependencies no longer in use.
   # $counter: integer with the number of existing dependencies when no HTML output is returned, and the number of missing dependencies when an HTML output is returned.
   # $numpathchg: integer with the number of cleaned up dependency paths.
   # \%existing: hash reference clean path -> 1 only for existing dependencies.
   # \%mapping: hash reference clean path -> original path for all dependencies.
   # @param {string} actionurl - The path to the handler, indicative of the context.
   # @param {string} state - Can contain HTML with hidden inputs that will be added to the output form.
   # @param {hash reference} allfiles - List of file info from lonnet::extract_embedded_items
   # @param {hash reference} codebase - undef, not modified by lonnet::extract_embedded_items ?
   # @param {hash reference} args - More parameters ! Possible keys: error_on_invalid_names (boolean), ignore_remote_references (boolean), current_path (string), docs_url (string), docs_title (string), context (string)
   # @return {Array} - array depending on the context (not a reference)
 sub ask_for_embedded_content {  sub ask_for_embedded_content {
       # NOTE: documentation was added afterwards, it could be wrong
     my ($actionurl,$state,$allfiles,$codebase,$args)=@_;      my ($actionurl,$state,$allfiles,$codebase,$args)=@_;
     my (%subdependencies,%dependencies,%mapping,%existing,%newfiles,%pathchanges,      my (%subdependencies,%dependencies,%mapping,%existing,%newfiles,%pathchanges,
         %currsubfile,%unused,$rem);          %currsubfile,%unused,$rem);
Line 10441  sub ask_for_embedded_content { Line 10958  sub ask_for_embedded_content {
     my $heading = &mt('Upload embedded files');      my $heading = &mt('Upload embedded files');
     my $buttontext = &mt('Upload');      my $buttontext = &mt('Upload');
   
       # fills these variables based on the context:
       # $navmap, $cdom, $cnum, $udom, $uname, $url, $toplevel, $getpropath,
       # $path, $fileloc, $title, $rem, $filename
     if ($env{'request.course.id'}) {      if ($env{'request.course.id'}) {
         if ($actionurl eq '/adm/dependencies') {          if ($actionurl eq '/adm/dependencies') {
             $navmap = Apache::lonnavmaps::navmap->new();              $navmap = Apache::lonnavmaps::navmap->new();
Line 10525  sub ask_for_embedded_content { Line 11045  sub ask_for_embedded_content {
         $fileloc = &Apache::lonnet::filelocation('',$toplevel).'/';          $fileloc = &Apache::lonnet::filelocation('',$toplevel).'/';
         $fileloc =~ s{^/}{};          $fileloc =~ s{^/}{};
     }      }
       
       # parses the dependency paths to get some info
       # fills $newfiles, $mapping, $subdependencies, $dependencies
       # $newfiles: hash URL -> 1 for new files or external URLs
       # (will be completed later)
       # $mapping:
       #   for external URLs: external URL -> external URL
       #   for relative paths: clean path -> original path
       # $subdependencies: hash clean path -> clean file name -> 1 for relative paths in subdirectories
       # $dependencies: hash clean or not file name -> 1 for relative paths not in subdirectories
     foreach my $file (keys(%{$allfiles})) {      foreach my $file (keys(%{$allfiles})) {
         my $embed_file;          my $embed_file;
         if (($path eq "/uploaded/$cdom/$cnum/portfolio/syllabus") && ($file =~ m{^\Q$path/\E(.+)$})) {          if (($path eq "/uploaded/$cdom/$cnum/portfolio/syllabus") && ($file =~ m{^\Q$path/\E(.+)$})) {
Line 10567  sub ask_for_embedded_content { Line 11097  sub ask_for_embedded_content {
             }              }
         }          }
     }      }
       
       # looks for all existing files in dependency subdirectories (from $subdependencies filled above)
       # and lists
       # fills $currsubfile, $pathchanges, $existing, $numexisting, $newfiles, $unused
       # $currsubfile: hash clean path -> file name -> 1 for all existing files in the path
       # $pathchanges: hash clean path -> 1 if the file in subdirectory exists and
       #                                    the path had to be cleaned up
       # $existing: hash clean path -> 1 if the file exists
       # $numexisting: number of keys in $existing
       # $newfiles: updated with clean path -> 1 for files in subdirectories that do not exist
       # $unused: only for /adm/dependencies, hash clean path -> 1 for existing files in
       #                                      dependency subdirectories that are
       #                                      not listed as dependencies, with some exceptions using $rem
     my $dirptr = 16384;      my $dirptr = 16384;
     foreach my $path (keys(%subdependencies)) {      foreach my $path (keys(%subdependencies)) {
         $currsubfile{$path} = {};          $currsubfile{$path} = {};
Line 10642  sub ask_for_embedded_content { Line 11185  sub ask_for_embedded_content {
             }              }
         }          }
     }      }
       
       # fills $currfile, hash file name -> 1 or [$size,$mtime]
       # for files in $url or $fileloc (target directory) in some contexts
     my %currfile;      my %currfile;
     if (($actionurl eq '/adm/portfolio') ||      if (($actionurl eq '/adm/portfolio') ||
         ($actionurl eq '/adm/coursegrp_portfolio')) {          ($actionurl eq '/adm/coursegrp_portfolio')) {
Line 10680  sub ask_for_embedded_content { Line 11226  sub ask_for_embedded_content {
             }              }
         }          }
     }      }
       # updates $pathchanges, $existing, $numexisting, $newfiles and $unused for files that
       # are not in subdirectories, using $currfile
     foreach my $file (keys(%dependencies)) {      foreach my $file (keys(%dependencies)) {
         if (exists($currfile{$file})) {          if (exists($currfile{$file})) {
             unless ($mapping{$file} eq $file) {              unless ($mapping{$file} eq $file) {
Line 10708  sub ask_for_embedded_content { Line 11256  sub ask_for_embedded_content {
             $unused{$file} = 1;              $unused{$file} = 1;
         }          }
     }      }
       
       # returns some results for coursedocs paste and syllabus rewrites ($output is undef)
     if (($actionurl eq '/adm/coursedocs') && (ref($args) eq 'HASH') &&      if (($actionurl eq '/adm/coursedocs') && (ref($args) eq 'HASH') &&
         ($args->{'context'} eq 'paste')) {          ($args->{'context'} eq 'paste')) {
         $counter = scalar(keys(%existing));          $counter = scalar(keys(%existing));
Line 10719  sub ask_for_embedded_content { Line 11269  sub ask_for_embedded_content {
         $numpathchg = scalar(keys(%pathchanges));          $numpathchg = scalar(keys(%pathchanges));
         return ($output,$counter,$numpathchg,\%existing,\%mapping);          return ($output,$counter,$numpathchg,\%existing,\%mapping);
     }      }
       
       # returns HTML otherwise, with dependency results and to ask for more uploads
       
       # $upload_output: missing dependencies (with upload form)
       # $modify_output: uploaded dependencies (in use)
       # $delete_output: files no longer in use (unused files are not listed for londocs, bug?)
     foreach my $embed_file (sort {lc($a) cmp lc($b)} keys(%newfiles)) {      foreach my $embed_file (sort {lc($a) cmp lc($b)} keys(%newfiles)) {
         if ($actionurl eq '/adm/dependencies') {          if ($actionurl eq '/adm/dependencies') {
             next if ($embed_file =~ m{^\w+://});              next if ($embed_file =~ m{^\w+://});
Line 14144  sub extract_categories { Line 14700  sub extract_categories {
                     $trailstr = &mt('Official courses (with institutional codes)');                      $trailstr = &mt('Official courses (with institutional codes)');
                 } elsif ($name eq 'communities') {                  } elsif ($name eq 'communities') {
                     $trailstr = &mt('Communities');                      $trailstr = &mt('Communities');
                   } elsif ($name eq 'placement') {
                       $trailstr = &mt('Placement Tests');
                 } else {                  } else {
                     $trailstr = $name;                      $trailstr = $name;
                 }                  }
Line 14282  sub assign_categories_table { Line 14840  sub assign_categories_table {
                     next if ($parent eq 'instcode');                      next if ($parent eq 'instcode');
                     if ($type eq 'Community') {                      if ($type eq 'Community') {
                         next unless ($parent eq 'communities');                          next unless ($parent eq 'communities');
                       } elsif ($type eq 'Placement') {
                           next unless ($parent eq 'placement');
                     } else {                      } else {
                         next if ($parent eq 'communities');                          next if (($parent eq 'communities') || ($parent eq 'placement'));
                     }                      }
                     my $css_class = $itemcount%2?' class="LC_odd_row"':'';                      my $css_class = $itemcount%2?' class="LC_odd_row"':'';
                     my $item = &escape($parent).'::0';                      my $item = &escape($parent).'::0';
Line 14296  sub assign_categories_table { Line 14856  sub assign_categories_table {
                     my $parent_title = $parent;                      my $parent_title = $parent;
                     if ($parent eq 'communities') {                      if ($parent eq 'communities') {
                         $parent_title = &mt('Communities');                          $parent_title = &mt('Communities');
                       } elsif ($parent eq 'placement') {
                           $parent_title = &mt('Placement Tests');
                     }                      }
                     $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="'.
Line 14731  sub construct_course { Line 15293  sub construct_course {
 #  #
 # Open course  # Open course
 #  #
     my $crstype = lc($args->{'crstype'});      my $showncrstype;
       if ($args->{'crstype'} eq 'Placement') {
           $showncrstype = 'placement test'; 
       } else {  
           $showncrstype = lc($args->{'crstype'});
       }
     my %cenv=();      my %cenv=();
     $$courseid=&Apache::lonnet::createcourse($args->{'course_domain'},      $$courseid=&Apache::lonnet::createcourse($args->{'course_domain'},
                                              $args->{'cdescr'},                                               $args->{'cdescr'},
Line 14748  sub construct_course { Line 15315  sub construct_course {
     # 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.
     $outcome .= &mt('New LON-CAPA [_1] ID: [_2]',$crstype,$$courseid).$linefeed;      $outcome .= &mt('New LON-CAPA [_1] ID: [_2]',$showncrstype,$$courseid).$linefeed;
     if ($$courseid =~ /^error:/) {      if ($$courseid =~ /^error:/) {
         return (0,$outcome);          return (0,$outcome);
     }      }
Line 14768  sub construct_course { Line 15335  sub construct_course {
 # Do the cloning  # Do the cloning
 #     #   
     if ($can_clone && $cloneid) {      if ($can_clone && $cloneid) {
  $clonemsg = &mt('Cloning [_1] from [_2]',$crstype,$clonehome);   $clonemsg = &mt('Cloning [_1] from [_2]',$showncrstype,$clonehome);
  if ($context ne 'auto') {   if ($context ne 'auto') {
     $clonemsg = '<span class="LC_success">'.$clonemsg.'</span>';      $clonemsg = '<span class="LC_success">'.$clonemsg.'</span>';
  }   }
Line 14967  sub construct_course { Line 15534  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 15073  sub construct_course { Line 15643  sub construct_course {
         $outcome .= ($fatal?$errtext:'write ok').$linefeed;          $outcome .= ($fatal?$errtext:'write ok').$linefeed;
     }      }
   
   # 
   # Set params for Placement Tests
   #
       if ($args->{'crstype'} eq 'Placement') {
          my %storecontent; 
          my $prefix=$$crsudom.'_'.$$crsunum.'.0.';
          my %defaults = (
                           buttonshide   => { value => 'yes',
                                              type => 'string_yesno',},
                           type          => { value => 'randomizetry',
                                              type  => 'string_questiontype',},
                           maxtries      => { value => 1,
                                              type => 'int_pos',},
                           problemstatus => { value => 'no',
                                              type  => 'string_problemstatus',},
                         );
          foreach my $key (keys(%defaults)) {
              $storecontent{$prefix.$key} = $defaults{$key}{'value'};
              $storecontent{$prefix.$key.'.type'} = $defaults{$key}{'type'};
          }
          &Apache::lonnet::cput
                    ('resourcedata',\%storecontent,$$crsudom,$$crsunum); 
       }
   
     return (1,$outcome);      return (1,$outcome);
 }  }
   
Line 15133  sub generate_code { Line 15727  sub generate_code {
 ############################################################  ############################################################
 ############################################################  ############################################################
   
 #SD  # Community, Course and Placement Test
 # only Community and Course, or anything else?  
 sub course_type {  sub course_type {
     my ($cid) = @_;      my ($cid) = @_;
     if (!defined($cid)) {      if (!defined($cid)) {
Line 15152  sub group_term { Line 15745  sub group_term {
     my %names = (      my %names = (
                   'Course' => 'group',                    'Course' => 'group',
                   'Community' => 'group',                    'Community' => 'group',
                     'Placement' => 'group',
                 );                  );
     return $names{$crstype};      return $names{$crstype};
 }  }
   
 sub course_types {  sub course_types {
     my @types = ('official','unofficial','community','textbook');      my @types = ('official','unofficial','community','textbook','placement');
     my %typename = (      my %typename = (
                          official   => 'Official course',                           official   => 'Official course',
                          unofficial => 'Unofficial course',                           unofficial => 'Unofficial course',
                          community  => 'Community',                           community  => 'Community',
                          textbook   => 'Textbook course',                           textbook   => 'Textbook course',
                            placement  => 'Placement test',
                    );                     );
     return (\@types,\%typename);      return (\@types,\%typename);
 }  }
Line 15377  sub init_user_environment { Line 15972  sub init_user_environment {
                                                   undef,\%userenv,\%domdef,\%is_adv);                                                    undef,\%userenv,\%domdef,\%is_adv);
         }          }
   
         foreach my $crstype ('official','unofficial','community','textbook') {          foreach my $crstype ('official','unofficial','community','textbook','placement') {
             $userenv{'canrequest.'.$crstype} =              $userenv{'canrequest.'.$crstype} =
                 &Apache::lonnet::usertools_access($username,$domain,$crstype,                  &Apache::lonnet::usertools_access($username,$domain,$crstype,
                                                   'reload','requestcourses',                                                    'reload','requestcourses',
Line 15625  sub build_filters { Line 16220  sub build_filters {
         $createdfilterform = &timebased_select_form('createdfilter',$filter);          $createdfilterform = &timebased_select_form('createdfilter',$filter);
     }      }
   
       my $prefix = $crstype;
       if ($crstype eq 'Placement') {
           $prefix = 'Placement Test'
       }
     my %lt = &Apache::lonlocal::texthash(      my %lt = &Apache::lonlocal::texthash(
                 'cac' => "$crstype Activity",                  'cac' => "$prefix Activity",
                 'ccr' => "$crstype Created",                  'ccr' => "$prefix Created",
                 'cde' => "$crstype Title",                  'cde' => "$prefix Title",
                 'cdo' => "$crstype Domain",                  'cdo' => "$prefix Domain",
                 'ins' => 'Institutional Code',                  'ins' => 'Institutional Code',
                 'inc' => 'Institutional Categorization',                  'inc' => 'Institutional Categorization',
                 'cow' => "$crstype Owner/Co-owner",                  'cow' => "$prefix Owner/Co-owner",
                 'cop' => "$crstype Personnel Includes",                  'cop' => "$prefix Personnel Includes",
                 'cog' => 'Type',                  'cog' => 'Type',
              );               );
   
Line 15641  sub build_filters { Line 16240  sub build_filters {
         my $typeval = 'Course';          my $typeval = 'Course';
         if ($crstype eq 'Community') {          if ($crstype eq 'Community') {
             $typeval = 'Community';              $typeval = 'Community';
           } elsif ($crstype eq 'Placement') {
               $typeval = 'Placement';
         }          }
         $typeselectform = '<input type="hidden" name="type" value="'.$typeval.'" />';          $typeselectform = '<input type="hidden" name="type" value="'.$typeval.'" />';
     } else {      } else {
Line 15649  sub build_filters { Line 16250  sub build_filters {
             $typeselectform .= ' onchange="'.$onchange.'"';              $typeselectform .= ' onchange="'.$onchange.'"';
         }          }
         $typeselectform .= '>'."\n";          $typeselectform .= '>'."\n";
         foreach my $posstype ('Course','Community') {          foreach my $posstype ('Course','Community','Placement') {
               my $shown;
               if ($posstype eq 'Placement') {
                   $shown = &mt('Placement Test');
               } else {
                   $shown = &mt($posstype);
               }
             $typeselectform.='<option value="'.$posstype.'"'.              $typeselectform.='<option value="'.$posstype.'"'.
                 ($posstype eq $crstype ? ' selected="selected" ' : ''). ">".&mt($posstype)."</option>\n";                  ($posstype eq $crstype ? ' selected="selected" ' : ''). ">".$shown."</option>\n";
         }          }
         $typeselectform.="</select>";          $typeselectform.="</select>";
     }      }
Line 16227  sub update_content_constraints { Line 16834  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,$valmatch) = split(/:/,$key);          my ($item,$name,$value) = 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 16402  sub symb_to_docspath { Line 17009  sub symb_to_docspath {
 sub captcha_display {  sub captcha_display {
     my ($context,$lonhost) = @_;      my ($context,$lonhost) = @_;
     my ($output,$error);      my ($output,$error);
     my ($captcha,$pubkey,$privkey) = &get_captcha_config($context,$lonhost);      my ($captcha,$pubkey,$privkey,$version) = 
           &get_captcha_config($context,$lonhost);
     if ($captcha eq 'original') {      if ($captcha eq 'original') {
         $output = &create_captcha();          $output = &create_captcha();
         unless ($output) {          unless ($output) {
             $error = 'captcha';              $error = 'captcha';
         }          }
     } elsif ($captcha eq 'recaptcha') {      } elsif ($captcha eq 'recaptcha') {
         $output = &create_recaptcha($pubkey);          $output = &create_recaptcha($pubkey,$version);
         unless ($output) {          unless ($output) {
             $error = 'recaptcha';              $error = 'recaptcha';
         }          }
     }      }
     return ($output,$error,$captcha);      return ($output,$error,$captcha,$version);
 }  }
   
 sub captcha_response {  sub captcha_response {
     my ($context,$lonhost) = @_;      my ($context,$lonhost) = @_;
     my ($captcha_chk,$captcha_error);      my ($captcha_chk,$captcha_error);
     my ($captcha,$pubkey,$privkey) = &get_captcha_config($context,$lonhost);      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') {
         $captcha_chk = &check_recaptcha($privkey);          $captcha_chk = &check_recaptcha($privkey,$version);
     } else {      } else {
         $captcha_chk = 1;          $captcha_chk = 1;
     }      }
Line 16433  sub captcha_response { Line 17041  sub captcha_response {
   
 sub get_captcha_config {  sub get_captcha_config {
     my ($context,$lonhost) = @_;      my ($context,$lonhost) = @_;
     my ($captcha,$pubkey,$privkey,$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);
     my $serverhomedom = &Apache::lonnet::host_domain($serverhomeID);      my $serverhomedom = &Apache::lonnet::host_domain($serverhomeID);
Line 16449  sub get_captcha_config { Line 17057  sub get_captcha_config {
                     }                      }
                     if ($privkey && $pubkey) {                      if ($privkey && $pubkey) {
                         $captcha = 'recaptcha';                          $captcha = 'recaptcha';
                           $version = $hashtocheck->{'recaptchaversion'};
                           if ($version ne '2') {
                               $version = 1;
                           }
                     } else {                      } else {
                         $captcha = 'original';                          $captcha = 'original';
                     }                      }
Line 16466  sub get_captcha_config { Line 17078  sub get_captcha_config {
             $privkey = $domconfhash{$serverhomedom.'.login.recaptchakeys_private'};              $privkey = $domconfhash{$serverhomedom.'.login.recaptchakeys_private'};
             if ($privkey && $pubkey) {              if ($privkey && $pubkey) {
                 $captcha = 'recaptcha';                  $captcha = 'recaptcha';
                   $version = $domconfhash{$serverhomedom.'.login.recaptchaversion'};
                   if ($version ne '2') {
                       $version = 1; 
                   }
             } else {              } else {
                 $captcha = 'original';                  $captcha = 'original';
             }              }
Line 16473  sub get_captcha_config { Line 17089  sub get_captcha_config {
             $captcha = 'original';              $captcha = 'original';
         }          }
     }      }
     return ($captcha,$pubkey,$privkey);      return ($captcha,$pubkey,$privkey,$version);
 }  }
   
 sub create_captcha {  sub create_captcha {
Line 16532  sub check_captcha { Line 17148  sub check_captcha {
 }  }
   
 sub create_recaptcha {  sub create_recaptcha {
     my ($pubkey) = @_;      my ($pubkey,$version) = @_;
     my $use_ssl;      if ($version >= 2) {
     if ($ENV{'SERVER_PORT'} == 443) {          return '<div class="g-recaptcha" data-sitekey="'.$pubkey.'"></div>';
         $use_ssl = 1;      } else {
     }          my $use_ssl;
     my $captcha = Captcha::reCAPTCHA->new;          if ($ENV{'SERVER_PORT'} == 443) {
     return $captcha->get_options_setter({theme => 'white'})."\n".              $use_ssl = 1;
            $captcha->get_html($pubkey,undef,$use_ssl).          }
            &mt('If the text is hard to read, [_1] will replace them.',          my $captcha = Captcha::reCAPTCHA->new;
                '<img src="/res/adm/pages/refresh.gif" alt="reCAPTCHA refresh" />').          return $captcha->get_options_setter({theme => 'white'})."\n".
            '<br /><br />';                 $captcha->get_html($pubkey,undef,$use_ssl).
                  &mt('If the text is hard to read, [_1] will replace them.',
                      '<img src="/res/adm/pages/refresh.gif" alt="reCAPTCHA refresh" />').
                  '<br /><br />';
       }
 }  }
   
 sub check_recaptcha {  sub check_recaptcha {
     my ($privkey) = @_;      my ($privkey,$version) = @_;
     my $captcha_chk;      my $captcha_chk;
     my $captcha = Captcha::reCAPTCHA->new;      if ($version >= 2) {
     my $captcha_result =          my $ua = LWP::UserAgent->new;
         $captcha->check_answer(          $ua->timeout(10);
                                 $privkey,          my %info = (
                                 $ENV{'REMOTE_ADDR'},                       secret   => $privkey, 
                                 $env{'form.recaptcha_challenge_field'},                       response => $env{'form.g-recaptcha-response'},
                                 $env{'form.recaptcha_response_field'},                       remoteip => $ENV{'REMOTE_ADDR'},
                               );                     );
     if ($captcha_result->{is_valid}) {          my $response = $ua->post('https://www.google.com/recaptcha/api/siteverify',\%info);
         $captcha_chk = 1;          if ($response->is_success)  {
               my $data = JSON::DWIW->from_json($response->decoded_content);
               if (ref($data) eq 'HASH') {
                   if ($data->{'success'}) {
                       $captcha_chk = 1;
                   }
               }
           }
       } else {
           my $captcha = Captcha::reCAPTCHA->new;
           my $captcha_result =
               $captcha->check_answer(
                                       $privkey,
                                       $ENV{'REMOTE_ADDR'},
                                       $env{'form.recaptcha_challenge_field'},
                                       $env{'form.recaptcha_response_field'},
                                     );
           if ($captcha_result->{is_valid}) {
               $captcha_chk = 1;
           }
     }      }
     return $captcha_chk;      return $captcha_chk;
 }  }
   
 sub emailusername_info {  sub emailusername_info {
     my @fields = ('firstname','lastname','institution','web','location','officialemail');      my @fields = ('firstname','lastname','institution','web','location','officialemail','id');
     my %titles = &Apache::lonlocal::texthash (      my %titles = &Apache::lonlocal::texthash (
                      lastname      => 'Last Name',                       lastname      => 'Last Name',
                      firstname     => 'First Name',                       firstname     => 'First Name',
Line 16571  sub emailusername_info { Line 17210  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 16651  sub des_decrypt { Line 17291  sub des_decrypt {
     } else {      } else {
         $cypher=new DES $keybin;          $cypher=new DES $keybin;
     }      }
     my $plaintext=      my $plaintext='';
         $cypher->decrypt(unpack("a8",pack("H16",substr($cyphertext,0,16))));      my $cypherlength = length($cyphertext);
     $plaintext.=      my $numchunks = int($cypherlength/32);
         $cypher->decrypt(unpack("a8",pack("H16",substr($cyphertext,16,16))));      for (my $j=0; $j<$numchunks; $j++) {
     $plaintext=substr($plaintext,1,ord(substr($plaintext,0,1)) );          my $start = $j*32;
           my $cypherblock = substr($cyphertext,$start,32);
           my $chunk =
               $cypher->decrypt(unpack("a8",pack("H16",substr($cypherblock,0,16))));
           $chunk .=
               $cypher->decrypt(unpack("a8",pack("H16",substr($cypherblock,16,16))));
           $chunk=substr($chunk,1,ord(substr($chunk,0,1)) );
           $plaintext .= $chunk;
       }
     return $plaintext;      return $plaintext;
 }  }
   

Removed from v.1.1228  
changed lines
  Added in v.1.1257


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