Diff for /loncom/interface/loncommon.pm between versions 1.1061 and 1.1183

version 1.1061, 2012/03/24 23:35:25 version 1.1183, 2014/03/17 13:38:57
Line 67  use Apache::lonhtmlcommon(); Line 67  use Apache::lonhtmlcommon();
 use Apache::loncoursedata();  use Apache::loncoursedata();
 use Apache::lontexconvert();  use Apache::lontexconvert();
 use Apache::lonclonecourse();  use Apache::lonclonecourse();
   use Apache::lonuserutils();
   use Apache::lonuserstate();
   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::Catalog;
   use Text::Aspell;
   use Authen::Captcha;
   use Captcha::reCAPTCHA;
   use Crypt::DES;
   use DynaLoader; # for Crypt::DES version
   
 # ---------------------------------------------- Designs  # ---------------------------------------------- Designs
 use vars qw(%defaultdesign);  use vars qw(%defaultdesign);
Line 154  sub ssi_with_retries { Line 162  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 188  BEGIN { Line 197  BEGIN {
             while (my $line = <$fh>) {              while (my $line = <$fh>) {
                 next if ($line=~/^\#/);                  next if ($line=~/^\#/);
                 chomp($line);                  chomp($line);
                 my ($key,$two,$country,$three,$enc,$val,$sup,$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 524  ENDAUTHORBRW Line 534  ENDAUTHORBRW
 }  }
   
 sub coursebrowser_javascript {  sub coursebrowser_javascript {
     my ($domainfilter,$sec_element,$formname,$role_element,$crstype) = @_;      my ($domainfilter,$sec_element,$formname,$role_element,$crstype,
           $credits_element) = @_;
     my $wintitle = 'Course_Browser';      my $wintitle = 'Course_Browser';
     if ($crstype eq 'Community') {      if ($crstype eq 'Community') {
         $wintitle = 'Community_Browser';          $wintitle = 'Community_Browser';
Line 587  sub coursebrowser_javascript { Line 598  sub coursebrowser_javascript {
     }      }
 $id_functions  $id_functions
 ENDSTDBRW  ENDSTDBRW
     if (($sec_element ne '') || ($role_element ne '')) {      if (($sec_element ne '') || ($role_element ne '') || ($credits_element ne '')) {
         $output .= &setsec_javascript($sec_element,$formname,$role_element);          $output .= &setsec_javascript($sec_element,$formname,$role_element,
                                         $credits_element);
     }      }
     $output .= '      $output .= '
 // ]]>  // ]]>
Line 657  if (!Array.prototype.indexOf) { Line 669  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 745  ENDUSERBRW Line 757  ENDUSERBRW
 }  }
   
 sub setsec_javascript {  sub setsec_javascript {
     my ($sec_element,$formname,$role_element) = @_;      my ($sec_element,$formname,$role_element,$credits_element) = @_;
     my (@courserolenames,@communityrolenames,$rolestr,$courserolestr,      my (@courserolenames,@communityrolenames,$rolestr,$courserolestr,
         $communityrolestr);          $communityrolestr);
     if ($role_element ne '') {      if ($role_element ne '') {
Line 840  function setRole(crstype) { Line 852  function setRole(crstype) {
 }  }
 |;  |;
     }      }
       if ($credits_element) {
           $setsections .= qq|
   function setCredits(defaultcredits) {
       document.$formname.$credits_element.value = defaultcredits;
       return;
   }
   |;
       }
     return $setsections;      return $setsections;
 }  }
   
Line 885  sub check_uncheck_jscript { Line 905  sub check_uncheck_jscript {
 function checkAll(field) {  function checkAll(field) {
     if (field.length > 0) {      if (field.length > 0) {
         for (i = 0; i < field.length; i++) {          for (i = 0; i < field.length; i++) {
             field[i].checked = true ;              if (!field[i].disabled) { 
                   field[i].checked = true;
               }
         }          }
     } else {      } else {
         field.checked = true          if (!field.disabled) { 
               field.checked = true;
           }
     }      }
 }  }
     
Line 990  sub select_language { Line 1014  sub select_language {
             $langchoices{$code} = &plainlanguagedescription($id);              $langchoices{$code} = &plainlanguagedescription($id);
         }          }
     }      }
       %langchoices = &Apache::lonlocal::texthash(%langchoices);
     return &select_form($selected,$name,\%langchoices);      return &select_form($selected,$name,\%langchoices);
 }  }
   
 =pod  =pod
   
   
   =item * &list_languages()
   
   Returns an array reference that is suitable for use in language prompters.
   Each array element is itself a two element array.  The first element
   is the language code.  The second element a descsriptiuon of the 
   language itself.  This is suitable for use in e.g.
   &Apache::edit::select_arg (once dereferenced that is).
   
   =cut 
   
   sub list_languages {
       my @lang_choices;
   
       foreach my $id (&languageids()) {
    my $code = &supportedlanguagecode($id);
    if ($code) {
       my $selector    = $supported_codes{$id};
       my $description = &plainlanguagedescription($id);
       push (@lang_choices, [$selector, $description]);
    }
       }
       return \@lang_choices;
   }
   
   =pod
   
 =item * &linked_select_forms(...)  =item * &linked_select_forms(...)
   
 linked_select_forms returns a string containing a <script></script> block  linked_select_forms returns a string containing a <script></script> block
Line 1021  linked_select_forms takes the following Line 1073  linked_select_forms takes the following
   
 =item * $menuorder, the order of values in the first menu  =item * $menuorder, the order of values in the first menu
   
   =item * $onchangefirst, additional javascript call to execute for an onchange
           event for the first <select> tag
   
   =item * $onchangesecond, additional javascript call to execute for an onchange
           event for the second <select> tag
   
 =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 1074  sub linked_select_forms { Line 1132  sub linked_select_forms {
         $secondselectname,           $secondselectname, 
         $hashref,          $hashref,
         $menuorder,          $menuorder,
           $onchangefirst,
           $onchangesecond
         ) = @_;          ) = @_;
     my $second = "document.$formname.$secondselectname";      my $second = "document.$formname.$secondselectname";
     my $first = "document.$formname.$firstselectname";      my $first = "document.$formname.$firstselectname";
Line 1130  function select1_changed() { Line 1190  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()\">\n";      $result .= "<select size=\"1\" name=\"$firstselectname\" onchange=\"select1_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 1143  END Line 1203  END
     $result .= "</select>\n";      $result .= "</select>\n";
     my %select2 = %{$hashref->{$firstdefault}->{'select2'}};      my %select2 = %{$hashref->{$firstdefault}->{'select2'}};
     $result .= $middletext;      $result .= $middletext;
     $result .= "<select size=\"1\" name=\"$secondselectname\">\n";      $result .= "<select size=\"1\" name=\"$secondselectname\"";
       if ($onchangesecond) {
           $result .= ' onchange="'.$onchangesecond.'"';
       }
       $result .= ">\n";
     my $seconddefault = $hashref->{$firstdefault}->{'default'};      my $seconddefault = $hashref->{$firstdefault}->{'default'};
           
     my @secondorder = sort(keys(%select2));      my @secondorder = sort(keys(%select2));
Line 1319  sub top_nav_help { Line 1383  sub top_nav_help {
     $text = &mt($text);      $text = &mt($text);
     my $stay_on_page = 1;      my $stay_on_page = 1;
   
     my $link = ($stay_on_page) ? "javascript:helpMenu('display')"      my ($link,$banner_link);
                      : "javascript:helpMenu('open')";      unless ($env{'request.noversionuri'} =~ m{^/adm/helpmenu}) {
     my $banner_link = &update_help_link(undef,undef,undef,undef,$stay_on_page);          $link = ($stay_on_page) ? "javascript:helpMenu('display')"
                            : "javascript:helpMenu('open')";
           $banner_link = &update_help_link(undef,undef,undef,undef,$stay_on_page);
       }
     my $title = &mt('Get help');      my $title = &mt('Get help');
       if ($link) {
     return <<"END";          return <<"END";
 $banner_link  $banner_link
  <a href="$link" title="$title">$text</a>  <a href="$link" title="$title">$text</a>
 END  END
       } else {
           return '&nbsp;'.$text.'&nbsp;';
       }
 }  }
   
 sub help_menu_js {  sub help_menu_js {
     my ($text) = @_;      my ($httphost) = @_;
     my $stayOnPage = 1;      my $stayOnPage = 1;
     my $width = 620;      my $width = 620;
     my $height = 600;      my $height = 600;
     my $helptopic=&general_help();      my $helptopic=&general_help();
     my $details_link = '/adm/help/'.$helptopic.'.hlp';      my $details_link = $httphost.'/adm/help/'.$helptopic.'.hlp';
     my $nothing=&Apache::lonhtmlcommon::javascript_nothing();      my $nothing=&Apache::lonhtmlcommon::javascript_nothing();
     my $start_page =      my $start_page =
         &Apache::loncommon::start_page('Help Menu', undef,          &Apache::loncommon::start_page('Help Menu', undef,
        {'frameset'    => 1,         {'frameset'    => 1,
  'js_ready'    => 1,   'js_ready'    => 1,
                                           '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 1374  function helpMenu(target) { Line 1444  function helpMenu(target) {
     return;      return;
 }  }
 function writeHelp(caller) {  function writeHelp(caller) {
     caller.document.writeln('$start_page<frame name="bannerframe"  src="'+banner_link+'" /><frame name="bodyframe" src="$details_link" /> $end_page')      caller.document.writeln('$start_page\\n<frame name="bannerframe" src="'+banner_link+'" marginwidth="0" marginheight="0" frameborder="0">\\n');
     caller.document.close()      caller.document.writeln('<frame name="bodyframe" src="$details_link" marginwidth="0" marginheight="0" frameborder="0">\\n$end_page');
     caller.focus()      caller.document.close();
       caller.focus();
 }  }
 // END LON-CAPA Internal -->  // END LON-CAPA Internal -->
 // ]]>  // ]]>
Line 1688  RESIZE Line 1759  RESIZE
   
 =head1 Excel and CSV file utility routines  =head1 Excel and CSV file utility routines
   
 =over 4  
   
 =cut  =cut
   
 ###############################################################  ###############################################################
Line 1697  RESIZE Line 1766  RESIZE
   
 =pod  =pod
   
   =over 4
   
 =item * &csv_translate($text)   =item * &csv_translate($text) 
   
 Translate $text to allow it to be output as a 'comma separated values'   Translate $text to allow it to be output as a 'comma separated values' 
Line 1981  sub select_form { Line 2052  sub select_form {
 # For display filters  # For display filters
   
 sub display_filter {  sub display_filter {
       my ($context) = @_;
     if (!$env{'form.show'}) { $env{'form.show'}=10; }      if (!$env{'form.show'}) { $env{'form.show'}=10; }
     if (!$env{'form.displayfilter'}) { $env{'form.displayfilter'}='currentfolder'; }      if (!$env{'form.displayfilter'}) { $env{'form.displayfilter'}='currentfolder'; }
     return '<span class="LC_nobreak"><label>'.&mt('Records [_1]',      my $phraseinput = 'hidden';
       my $includeinput = 'hidden';
       my ($checked,$includetypestext);
       if ($env{'form.displayfilter'} eq 'containing') {
           $phraseinput = 'text'; 
           if ($context eq 'parmslog') {
               $includeinput = 'checkbox';
               if ($env{'form.includetypes'}) {
                   $checked = ' checked="checked"';
               }
               $includetypestext = &mt('Include parameter types');
           }
       } else {
           $includetypestext = '&nbsp;';
       }
       my ($additional,$secondid,$thirdid);
       if ($context eq 'parmslog') {
           $additional = 
               '<label><input type="'.$includeinput.'" name="includetypes"'. 
               $checked.' name="includetypes" value="1" id="includetypes" />'.
               '&nbsp;<span id="includetypestext">'.$includetypestext.'</span>'.
               '</label>';
           $secondid = 'includetypes';
           $thirdid = 'includetypestext';
       }
       my $onchange = "javascript:toggleHistoryOptions(this,'containingphrase','$context',
                                                       '$secondid','$thirdid')";
       return '<span class="LC_nobreak"><label>'.&mt('Records: [_1]',
        &Apache::lonmeta::selectbox('show',$env{'form.show'},undef,         &Apache::lonmeta::selectbox('show',$env{'form.show'},undef,
    (&mt('all'),10,20,50,100,1000,10000))).     (&mt('all'),10,20,50,100,1000,10000))).
    '</label></span> <span class="LC_nobreak">'.     '</label></span> <span class="LC_nobreak">'.
            &mt('Filter [_1]',             &mt('Filter: [_1]',
    &select_form($env{'form.displayfilter'},     &select_form($env{'form.displayfilter'},
  'displayfilter',   'displayfilter',
  {'currentfolder' => 'Current folder/page',   {'currentfolder' => 'Current folder/page',
  'containing' => 'Containing phrase',   'containing' => 'Containing phrase',
  'none' => 'None'})).   'none' => 'None'},$onchange)).'&nbsp;'.
  '<input type="text" name="containingphrase" size="30" value="'.&HTML::Entities::encode($env{'form.containingphrase'}).'" /></span>';   '<input type="'.$phraseinput.'" name="containingphrase" id="containingphrase" size="30" value="'.
                            &HTML::Entities::encode($env{'form.containingphrase'}).
                            '" />'.$additional;
   }
   
   sub display_filter_js {
       my $includetext = &mt('Include parameter types');
       return <<"ENDJS";
     
   function toggleHistoryOptions(setter,firstid,context,secondid,thirdid) {
       var firstType = 'hidden';
       if (setter.options[setter.selectedIndex].value == 'containing') {
           firstType = 'text';
       }
       firstObject = document.getElementById(firstid);
       if (typeof(firstObject) == 'object') {
           if (firstObject.type != firstType) {
               changeInputType(firstObject,firstType);
           }
       }
       if (context == 'parmslog') {
           var secondType = 'hidden';
           if (firstType == 'text') {
               secondType = 'checkbox';
           }
           secondObject = document.getElementById(secondid);  
           if (typeof(secondObject) == 'object') {
               if (secondObject.type != secondType) {
                   changeInputType(secondObject,secondType);
               }
           }
           var textItem = document.getElementById(thirdid);
           var currtext = textItem.innerHTML;
           var newtext;
           if (firstType == 'text') {
               newtext = '$includetext';
           } else {
               newtext = '&nbsp;';
           }
           if (currtext != newtext) {
               textItem.innerHTML = newtext;
           }
       }
       return;
   }
   
   function changeInputType(oldObject,newType) {
       var newObject = document.createElement('input');
       newObject.type = newType;
       if (oldObject.size) {
           newObject.size = oldObject.size;
       }
       if (oldObject.value) {
           newObject.value = oldObject.value;
       }
       if (oldObject.name) {
           newObject.name = oldObject.name;
       }
       if (oldObject.id) {
           newObject.id = oldObject.id;
       }
       oldObject.parentNode.replaceChild(newObject,oldObject);
       return;
   }
   
   ENDJS
 }  }
   
 sub gradeleveldescription {  sub gradeleveldescription {
Line 2037  sub select_level_form { Line 2201  sub select_level_form {
   
 =pod  =pod
   
 =item * &select_dom_form($defdom,$name,$includeempty,$showdomdesc,$onchange,$incdoms)  =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 2050  If the $showdomdesc flag is set, the dom Line 2214  If the $showdomdesc flag is set, the dom
   
 The optional $onchange argument specifies what should occur if the domain selector is changed, e.g., 'this.form.submit()' if the form is to be automatically submitted.  The optional $onchange argument specifies what should occur if the domain selector is changed, e.g., 'this.form.submit()' if the form is to be automatically submitted.
   
 The optional $incdoms is a reference to an array of domains which will be the only available options.   The optional $incdoms is a reference to an array of domains which will be the only available options.
   
   The optional $excdoms is a reference to an array of domains which will be excluded from the available options.
   
 =cut  =cut
   
 #-------------------------------------------  #-------------------------------------------
 sub select_dom_form {  sub select_dom_form {
     my ($defdom,$name,$includeempty,$showdomdesc,$onchange,$incdoms) = @_;      my ($defdom,$name,$includeempty,$showdomdesc,$onchange,$incdoms,$excdoms) = @_;
     if ($onchange) {      if ($onchange) {
         $onchange = ' onchange="'.$onchange.'"';          $onchange = ' onchange="'.$onchange.'"';
     }      }
     my @domains;      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});
     } else {      } else {
         @domains = sort {lc($a) cmp lc($b)} (&Apache::lonnet::all_domains());          @domains = sort {lc($a) cmp lc($b)} (&Apache::lonnet::all_domains());
     }      }
     if ($includeempty) { @domains=('',@domains); }      if ($includeempty) { @domains=('',@domains); }
       if (ref($excdoms) eq 'ARRAY') {
           map { $exclude{$_} = 1; } @{$excdoms}; 
       }
     my $selectdomain = "<select name=\"$name\" size=\"1\"$onchange>\n";      my $selectdomain = "<select name=\"$name\" size=\"1\"$onchange>\n";
     foreach my $dom (@domains) {      foreach my $dom (@domains) {
           next if ($exclude{$dom});
         $selectdomain.="<option value=\"$dom\" ".          $selectdomain.="<option value=\"$dom\" ".
             ($dom eq $defdom ? 'selected="selected" ' : '').'>'.$dom;              ($dom eq $defdom ? 'selected="selected" ' : '').'>'.$dom;
         if ($showdomdesc) {          if ($showdomdesc) {
Line 2189  Outputs: Line 2359  Outputs:
   
 =item * $clientos  =item * $clientos
   
   =item * $clientmobile
   
   =item * $clientinfo
   
 =back  =back
   
 =back   =back 
Line 2207  sub decode_user_agent { Line 2381  sub decode_user_agent {
     my $clientversion='0';      my $clientversion='0';
     my $clientmathml='';      my $clientmathml='';
     my $clientunicode='0';      my $clientunicode='0';
       my $clientmobile=0;
     for (my $i=0;$i<=$#browsertype;$i++) {      for (my $i=0;$i<=$#browsertype;$i++) {
         my ($bname,$match,$notmatch,$vreg,$minv,$univ)=split(/\:/,$browsertype[$i]);          my ($bname,$match,$notmatch,$vreg,$minv,$univ)=split(/\:/,$browsertype[$i]);
  if (($httpbrowser=~/$match/i)  && ($httpbrowser!~/$notmatch/i)) {   if (($httpbrowser=~/$match/i)  && ($httpbrowser!~/$notmatch/i)) {
Line 2218  sub decode_user_agent { Line 2393  sub decode_user_agent {
  }   }
     }      }
     my $clientos='unknown';      my $clientos='unknown';
       my $clientinfo;
     if (($httpbrowser=~/linux/i) ||      if (($httpbrowser=~/linux/i) ||
         ($httpbrowser=~/unix/i) ||          ($httpbrowser=~/unix/i) ||
         ($httpbrowser=~/ux/i) ||          ($httpbrowser=~/ux/i) ||
Line 2229  sub decode_user_agent { Line 2405  sub decode_user_agent {
         ($httpbrowser=~/powerpc/i)) { $clientos='mac'; }          ($httpbrowser=~/powerpc/i)) { $clientos='mac'; }
     if ($httpbrowser=~/win/i) { $clientos='win'; }      if ($httpbrowser=~/win/i) { $clientos='win'; }
     if ($httpbrowser=~/embed/i) { $clientos='pda'; }      if ($httpbrowser=~/embed/i) { $clientos='pda'; }
       if ($httpbrowser=~/(Android|iPod|iPad|iPhone|webOS|Blackberry|Windows Phone|Opera m(?:ob|in)|Fennec)/i) {
           $clientmobile=lc($1);
       }
       if ($httpbrowser=~ m{Firefox/(\d+\.\d+)}) {
           $clientinfo = 'firefox-'.$1;
       } elsif ($httpbrowser=~ m{chromeframe/(\d+\.\d+)\.}) {
           $clientinfo = 'chromeframe-'.$1;
       }
     return ($httpbrowser,$clientbrowser,$clientversion,$clientmathml,      return ($httpbrowser,$clientbrowser,$clientversion,$clientmathml,
             $clientunicode,$clientos,);              $clientunicode,$clientos,$clientmobile,$clientinfo);
 }  }
   
 ###############################################################  ###############################################################
Line 2382  END Line 2566  END
     return $result;      return $result;
 }  }
   
 sub authform_authorwarning{  sub authform_authorwarning {
     my $result='';      my $result='';
     $result='<i>'.      $result='<i>'.
         &mt('As a general rule, only authors or co-authors should be '.          &mt('As a general rule, only authors or co-authors should be '.
Line 2391  sub authform_authorwarning{ Line 2575  sub authform_authorwarning{
     return $result;      return $result;
 }  }
   
 sub authform_nochange{    sub authform_nochange {
     my %in = (      my %in = (
               formname => 'document.cu',                formname => 'document.cu',
               kerb_def_dom => 'MSU.EDU',                kerb_def_dom => 'MSU.EDU',
               @_,                @_,
           );            );
     my ($authnum,%can_assign) =  &get_assignable_auth($in{'domain'});       my ($authnum,%can_assign) = &get_assignable_auth($in{'domain'});
     my $result;      my $result;
     if (keys(%can_assign) == 0) {      if (!$authnum) {
         $result = &mt('Under you current role you are not permitted to change login settings for this user');            $result = &mt('Under your current role you are not permitted to change login settings for this user');
     } else {      } else {
         $result = '<label>'.&mt('[_1] Do not change login data',          $result = '<label>'.&mt('[_1] Do not change login data',
                   '<input type="radio" name="login" value="nochange" '.                    '<input type="radio" name="login" value="nochange" '.
Line 2420  sub authform_kerberos { Line 2604  sub authform_kerberos {
               );                );
     my ($check4,$check5,$krbcheck,$krbarg,$krbver,$result,$authtype,      my ($check4,$check5,$krbcheck,$krbarg,$krbver,$result,$authtype,
         $autharg,$jscall);          $autharg,$jscall);
     my ($authnum,%can_assign) =  &get_assignable_auth($in{'domain'});      my ($authnum,%can_assign) = &get_assignable_auth($in{'domain'});
     if ($in{'kerb_def_auth'} eq 'krb5') {      if ($in{'kerb_def_auth'} eq 'krb5') {
        $check5 = ' checked="checked"';         $check5 = ' checked="checked"';
     } else {      } else {
Line 2470  sub authform_kerberos { Line 2654  sub authform_kerberos {
         if (defined($in{'mode'})) {          if (defined($in{'mode'})) {
             if ($in{'mode'} eq 'modifycourse') {              if ($in{'mode'} eq 'modifycourse') {
                 if ($authnum == 1) {                  if ($authnum == 1) {
                     $authtype = '<input type="hidden" name="login" value="krb" />';                      $authtype = '<input type="radio" name="login" value="krb" />';
                 }                  }
             }              }
         }          }
Line 2482  sub authform_kerberos { Line 2666  sub authform_kerberos {
                     $krbcheck.' />';                      $krbcheck.' />';
     }      }
     if (($can_assign{'krb4'} && $can_assign{'krb5'}) ||      if (($can_assign{'krb4'} && $can_assign{'krb5'}) ||
         ($can_assign{'krb4'} && !$can_assign{'krb5'} &&           ($can_assign{'krb4'} && !$can_assign{'krb5'} &&
          $in{'curr_authtype'} eq 'krb5') ||           $in{'curr_authtype'} eq 'krb5') ||
         (!$can_assign{'krb4'} && $can_assign{'krb5'} &&           (!$can_assign{'krb4'} && $can_assign{'krb5'} &&
          $in{'curr_authtype'} eq 'krb4')) {           $in{'curr_authtype'} eq 'krb4')) {
         $result .= &mt          $result .= &mt
         ('[_1] Kerberos authenticated with domain [_2] '.          ('[_1] Kerberos authenticated with domain [_2] '.
Line 2520  sub authform_kerberos { Line 2704  sub authform_kerberos {
     return $result;      return $result;
 }  }
   
 sub authform_internal{    sub authform_internal {
     my %in = (      my %in = (
                 formname => 'document.cu',                  formname => 'document.cu',
                 kerb_def_dom => 'MSU.EDU',                  kerb_def_dom => 'MSU.EDU',
                 @_,                  @_,
                 );                  );
     my ($intcheck,$intarg,$result,$authtype,$autharg,$jscall);      my ($intcheck,$intarg,$result,$authtype,$autharg,$jscall);
     my ($authnum,%can_assign) =  &get_assignable_auth($in{'domain'});      my ($authnum,%can_assign) = &get_assignable_auth($in{'domain'});
     if (defined($in{'curr_authtype'})) {      if (defined($in{'curr_authtype'})) {
         if ($in{'curr_authtype'} eq 'int') {          if ($in{'curr_authtype'} eq 'int') {
             if ($can_assign{'int'}) {              if ($can_assign{'int'}) {
Line 2556  sub authform_internal{ Line 2740  sub authform_internal{
         if (defined($in{'mode'})) {          if (defined($in{'mode'})) {
             if ($in{'mode'} eq 'modifycourse') {              if ($in{'mode'} eq 'modifycourse') {
                 if ($authnum == 1) {                  if ($authnum == 1) {
                     $authtype = '<input type="hidden" name="login" value="int" />';                      $authtype = '<input type="radio" name="login" value="int" />';
                 }                  }
             }              }
         }          }
Line 2575  sub authform_internal{ Line 2759  sub authform_internal{
     return $result;      return $result;
 }  }
   
 sub authform_local{    sub authform_local {
     my %in = (      my %in = (
               formname => 'document.cu',                formname => 'document.cu',
               kerb_def_dom => 'MSU.EDU',                kerb_def_dom => 'MSU.EDU',
               @_,                @_,
               );                );
     my ($loccheck,$locarg,$result,$authtype,$autharg,$jscall);      my ($loccheck,$locarg,$result,$authtype,$autharg,$jscall);
     my ($authnum,%can_assign) =  &get_assignable_auth($in{'domain'});      my ($authnum,%can_assign) = &get_assignable_auth($in{'domain'});
     if (defined($in{'curr_authtype'})) {      if (defined($in{'curr_authtype'})) {
         if ($in{'curr_authtype'} eq 'loc') {          if ($in{'curr_authtype'} eq 'loc') {
             if ($can_assign{'loc'}) {              if ($can_assign{'loc'}) {
Line 2611  sub authform_local{ Line 2795  sub authform_local{
         if (defined($in{'mode'})) {          if (defined($in{'mode'})) {
             if ($in{'mode'} eq 'modifycourse') {              if ($in{'mode'} eq 'modifycourse') {
                 if ($authnum == 1) {                  if ($authnum == 1) {
                     $authtype = '<input type="hidden" name="login" value="loc" />';                      $authtype = '<input type="radio" name="login" value="loc" />';
                 }                  }
             }              }
         }          }
Line 2629  sub authform_local{ Line 2813  sub authform_local{
     return $result;      return $result;
 }  }
   
 sub authform_filesystem{    sub authform_filesystem {
     my %in = (      my %in = (
               formname => 'document.cu',                formname => 'document.cu',
               kerb_def_dom => 'MSU.EDU',                kerb_def_dom => 'MSU.EDU',
               @_,                @_,
               );                );
     my ($fsyscheck,$result,$authtype,$autharg,$jscall);      my ($fsyscheck,$result,$authtype,$autharg,$jscall);
     my ($authnum,%can_assign) =  &get_assignable_auth($in{'domain'});      my ($authnum,%can_assign) = &get_assignable_auth($in{'domain'});
     if (defined($in{'curr_authtype'})) {      if (defined($in{'curr_authtype'})) {
         if ($in{'curr_authtype'} eq 'fsys') {          if ($in{'curr_authtype'} eq 'fsys') {
             if ($can_assign{'fsys'}) {              if ($can_assign{'fsys'}) {
Line 2662  sub authform_filesystem{ Line 2846  sub authform_filesystem{
         if (defined($in{'mode'})) {          if (defined($in{'mode'})) {
             if ($in{'mode'} eq 'modifycourse') {              if ($in{'mode'} eq 'modifycourse') {
                 if ($authnum == 1) {                  if ($authnum == 1) {
                     $authtype = '<input type="hidden" name="login" value="fsys" />';                      $authtype = '<input type="radio" name="login" value="fsys" />';
                 }                  }
             }              }
         }          }
Line 2893  sub get_related_words { Line 3077  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 3090  sub screenname { Line 3334  sub screenname {
 # ------------------------------------------------------------- Confirm Wrapper  # ------------------------------------------------------------- Confirm Wrapper
 =pod  =pod
   
 =item confirmwrapper  =item * &confirmwrapper($message)
   
 Wrap messages about completion of operation in box  Wrap messages about completion of operation in box
   
Line 3129  sub noteswrapper { Line 3373  sub noteswrapper {
 # ------------------------------------------------------------- Aboutme Wrapper  # ------------------------------------------------------------- Aboutme Wrapper
   
 sub aboutmewrapper {  sub aboutmewrapper {
     my ($link,$username,$domain,$target)=@_;      my ($link,$username,$domain,$target,$class)=@_;
     if (!defined($username)  && !defined($domain)) {      if (!defined($username)  && !defined($domain)) {
         return;          return;
     }      }
     return '<a href="/adm/'.$domain.'/'.$username.'/aboutme?forcestudent=1"'.      return '<a href="/adm/'.$domain.'/'.$username.'/aboutme"'.
  ($target?' target="$target"':'').' title="'.&mt("View this user's personal information page").'">'.$link.'</a>';   ($target?' target="'.$target.'"':'').($class?' class="'.$class.'"':'').' title="'.&mt("View this user's personal information page").'">'.$link.'</a>';
 }  }
   
 # ------------------------------------------------------------ Syllabus Wrapper  # ------------------------------------------------------------ Syllabus Wrapper
Line 3649  sub get_previous_attempt { Line 3893  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 3665  sub get_previous_attempt { Line 3909  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 3686  sub get_previous_attempt { Line 3930  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 3713  sub format_previous_attempt_value { Line 3959  sub format_previous_attempt_value {
             }               } 
         }          }
     } else {      } else {
  $value = &unescape($value);          $value = &HTML::Entities::encode(&unescape($value), '"<>&');
     }      }
     return $value;      return $value;
 }  }
Line 3990  sub findallcourses { Line 4236  sub findallcourses {
         $udom = $env{'user.domain'};          $udom = $env{'user.domain'};
     }      }
     if (($uname ne $env{'user.name'}) || ($udom ne $env{'user.domain'})) {      if (($uname ne $env{'user.name'}) || ($udom ne $env{'user.domain'})) {
         my $extra = &Apache::lonnet::freeze_escape({'skipcheck' => 1});          my %roleshash = &Apache::lonnet::dump('roles',$udom,$uname);
         my %roleshash = &Apache::lonnet::dump('roles',$udom,$uname,'.',undef,  
                                               $extra);  
         if (!%roles) {          if (!%roles) {
             %roles = (              %roles = (
                        cc => 1,                         cc => 1,
Line 4076  sub findallcourses { Line 4320  sub findallcourses {
 ###############################################  ###############################################
   
 sub blockcheck {  sub blockcheck {
     my ($setters,$activity,$uname,$udom) = @_;      my ($setters,$activity,$uname,$udom,$url) = @_;
   
     if (!defined($udom)) {      if (!defined($udom)) {
         $udom = $env{'user.domain'};          $udom = $env{'user.domain'};
Line 4088  sub blockcheck { Line 4332  sub blockcheck {
     # If uname and udom are for a course, check for blocks in the course.      # If uname and udom are for a course, check for blocks in the course.
   
     if (&Apache::lonnet::is_course($udom,$uname)) {      if (&Apache::lonnet::is_course($udom,$uname)) {
         my %records = &Apache::lonnet::dump('comm_block',$udom,$uname);          my ($startblock,$endblock,$triggerblock) = 
         my ($startblock,$endblock)=&get_blocks($setters,$activity,$udom,$uname);              &get_blocks($setters,$activity,$udom,$uname,$url);
         return ($startblock,$endblock);          return ($startblock,$endblock,$triggerblock);
     }      }
   
     my $startblock = 0;      my $startblock = 0;
     my $endblock = 0;      my $endblock = 0;
       my $triggerblock = '';
     my %live_courses = &findallcourses(undef,$uname,$udom);      my %live_courses = &findallcourses(undef,$uname,$udom);
   
     # If uname is for a user, and activity is course-specific, i.e.,      # If uname is for a user, and activity is course-specific, i.e.,
Line 4209  sub blockcheck { Line 4454  sub blockcheck {
         # Retrieve blocking times and identity of locker for course          # Retrieve blocking times and identity of locker for course
         # of specified user, unless user has 'evb' privilege.          # of specified user, unless user has 'evb' privilege.
                   
         my ($start,$end)=&get_blocks($setters,$activity,$cdom,$cnum);          my ($start,$end,$trigger) = 
               &get_blocks($setters,$activity,$cdom,$cnum,$url);
         if (($start != 0) &&           if (($start != 0) && 
             (($startblock == 0) || ($startblock > $start))) {              (($startblock == 0) || ($startblock > $start))) {
             $startblock = $start;              $startblock = $start;
               if ($trigger ne '') {
                   $triggerblock = $trigger;
               }
         }          }
         if (($end != 0)  &&          if (($end != 0)  &&
             (($endblock == 0) || ($endblock < $end))) {              (($endblock == 0) || ($endblock < $end))) {
             $endblock = $end;              $endblock = $end;
               if ($trigger ne '') {
                   $triggerblock = $trigger;
               }
         }          }
     }      }
     return ($startblock,$endblock);      return ($startblock,$endblock,$triggerblock);
 }  }
   
 sub get_blocks {  sub get_blocks {
     my ($setters,$activity,$cdom,$cnum) = @_;      my ($setters,$activity,$cdom,$cnum,$url) = @_;
     my $startblock = 0;      my $startblock = 0;
     my $endblock = 0;      my $endblock = 0;
       my $triggerblock = '';
     my $course = $cdom.'_'.$cnum;      my $course = $cdom.'_'.$cnum;
     $setters->{$course} = {};      $setters->{$course} = {};
     $setters->{$course}{'staff'} = [];      $setters->{$course}{'staff'} = [];
     $setters->{$course}{'times'} = [];      $setters->{$course}{'times'} = [];
     my %records = &Apache::lonnet::dump('comm_block',$cdom,$cnum);      $setters->{$course}{'triggers'} = [];
     foreach my $record (keys(%records)) {      my (@blockers,%triggered);
         my ($start,$end) = ($record =~ m/^(\d+)____(\d+)$/);      my $now = time;
         if ($start <= time && $end >= time) {      my %commblocks = &Apache::lonnet::get_comm_blocks($cdom,$cnum);
             my ($staff_name,$staff_dom,$title,$blocks) =      if ($activity eq 'docs') {
                 &parse_block_record($records{$record});          @blockers = &Apache::lonnet::has_comm_blocking('bre',undef,$url,\%commblocks);
             if ($blocks->{$activity} eq 'on') {          foreach my $block (@blockers) {
                 push(@{$$setters{$course}{'staff'}},[$staff_name,$staff_dom]);              if ($block =~ /^firstaccess____(.+)$/) {
                 push(@{$$setters{$course}{'times'}}, [$start,$end]);                  my $item = $1;
                 if ( ($startblock == 0) || ($startblock > $start) ) {                  my $type = 'map';
                     $startblock = $start;                  my $timersymb = $item;
                   if ($item eq 'course') {
                       $type = 'course';
                   } elsif ($item =~ /___\d+___/) {
                       $type = 'resource';
                   } else {
                       $timersymb = &Apache::lonnet::symbread($item);
                 }                  }
                 if ( ($endblock == 0) || ($endblock < $end) ) {                  my $start = $env{'course.'.$cdom.'_'.$cnum.'.firstaccess.'.$timersymb};
                     $endblock = $end;                  my $end = $start + $env{'course.'.$cdom.'_'.$cnum.'.timerinterval.'.$timersymb};
                   $triggered{$block} = {
                                          start => $start,
                                          end   => $end,
                                          type  => $type,
                                        };
               }
           }
       } else {
           foreach my $block (keys(%commblocks)) {
               if ($block =~ m/^(\d+)____(\d+)$/) { 
                   my ($start,$end) = ($1,$2);
                   if ($start <= time && $end >= time) {
                       if (ref($commblocks{$block}) eq 'HASH') {
                           if (ref($commblocks{$block}{'blocks'}) eq 'HASH') {
                               if ($commblocks{$block}{'blocks'}{$activity} eq 'on') {
                                   unless(grep(/^\Q$block\E$/,@blockers)) {
                                       push(@blockers,$block);
                                   }
                               }
                           }
                       }
                 }                  }
               } elsif ($block =~ /^firstaccess____(.+)$/) {
                   my $item = $1;
                   my $timersymb = $item; 
                   my $type = 'map';
                   if ($item eq 'course') {
                       $type = 'course';
                   } elsif ($item =~ /___\d+___/) {
                       $type = 'resource';
                   } else {
                       $timersymb = &Apache::lonnet::symbread($item);
                   }
                   my $start = $env{'course.'.$cdom.'_'.$cnum.'.firstaccess.'.$timersymb};
                   my $end = $start + $env{'course.'.$cdom.'_'.$cnum.'.timerinterval.'.$timersymb}; 
                   if ($start && $end) {
                       if (($start <= time) && ($end >= time)) {
                           unless (grep(/^\Q$block\E$/,@blockers)) {
                               push(@blockers,$block);
                               $triggered{$block} = {
                                                      start => $start,
                                                      end   => $end,
                                                      type  => $type,
                                                    };
                           }
                       }
                   }
               }
           }
       }
       foreach my $blocker (@blockers) {
           my ($staff_name,$staff_dom,$title,$blocks) =
               &parse_block_record($commblocks{$blocker});
           push(@{$$setters{$course}{'staff'}},[$staff_name,$staff_dom]);
           my ($start,$end,$triggertype);
           if ($blocker =~ m/^(\d+)____(\d+)$/) {
               ($start,$end) = ($1,$2);
           } elsif (ref($triggered{$blocker}) eq 'HASH') {
               $start = $triggered{$blocker}{'start'};
               $end = $triggered{$blocker}{'end'};
               $triggertype = $triggered{$blocker}{'type'};
           }
           if ($start) {
               push(@{$$setters{$course}{'times'}}, [$start,$end]);
               if ($triggertype) {
                   push(@{$$setters{$course}{'triggers'}},$triggertype);
               } else {
                   push(@{$$setters{$course}{'triggers'}},0);
               }
               if ( ($startblock == 0) || ($startblock > $start) ) {
                   $startblock = $start;
                   if ($triggertype) {
                       $triggerblock = $blocker;
                   }
               }
               if ( ($endblock == 0) || ($endblock < $end) ) {
                  $endblock = $end;
                  if ($triggertype) {
                      $triggerblock = $blocker;
                  }
             }              }
         }          }
     }      }
     return ($startblock,$endblock);      return ($startblock,$endblock,$triggerblock);
 }  }
   
 sub parse_block_record {  sub parse_block_record {
Line 4272  sub parse_block_record { Line 4610  sub parse_block_record {
 }  }
   
 sub blocking_status {  sub blocking_status {
     my ($activity,$uname,$udom) = @_;      my ($activity,$uname,$udom,$url) = @_;
     my %setters;      my %setters;
   
 # check for active blocking  # check for active blocking
     my ($startblock,$endblock)=&blockcheck(\%setters,$activity,$uname,$udom);      my ($startblock,$endblock,$triggerblock) = 
           &blockcheck(\%setters,$activity,$uname,$udom,$url);
     my $blocked = $startblock && $endblock ? 1 : 0;      my $blocked = 0;
       if ($startblock && $endblock) {
           $blocked = 1;
       }
   
 # caller just wants to know whether a block is active  # caller just wants to know whether a block is active
     if (!wantarray) { return $blocked; }      if (!wantarray) { return $blocked; }
Line 4286  sub blocking_status { Line 4627  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
     $querystring .= "&amp;udom=$udom"      if $udom;      if ($activity eq 'port') {
     $querystring .= "&amp;uname=$uname"    if $uname;          $querystring .= "&amp;udom=$udom"      if $udom;
           $querystring .= "&amp;uname=$uname"    if $uname;
       } elsif ($activity eq 'docs') {
           $querystring .= '&amp;url='.&HTML::Entities::encode($url,'&"');
       }
   
     my $output .= <<'END_MYBLOCK';      my $output .= <<'END_MYBLOCK';
 function openWindow(url, wdwName, w, h, toolbar,scrollbar) {  function openWindow(url, wdwName, w, h, toolbar,scrollbar) {
Line 4302  END_MYBLOCK Line 4647  END_MYBLOCK
     $output = Apache::lonhtmlcommon::scripttag($output);      $output = Apache::lonhtmlcommon::scripttag($output);
       
     my $popupUrl = "/adm/blockingstatus/$querystring";      my $popupUrl = "/adm/blockingstatus/$querystring";
     my $text = mt('Communication Blocked');      my $text = &mt('Communication Blocked');
       if ($activity eq 'docs') {
           $text = &mt('Content Access Blocked');
       } elsif ($activity eq 'printout') {
           $text = &mt('Printing Blocked');
       }
     $output .= <<"END_BLOCK";      $output .= <<"END_BLOCK";
 <div class='LC_comblock'>  <div class='LC_comblock'>
   <a onclick='openWindow("$popupUrl","Blocking Table",600,300,"no","no");return false;' href='/adm/blockingstatus/$querystring'    <a onclick='openWindow("$popupUrl","Blocking Table",600,300,"no","no");return false;' href='/adm/blockingstatus/$querystring'
Line 4605  sub designparm { Line 4954  sub designparm {
   
 Inputs: $url (usually will be undef).  Inputs: $url (usually will be undef).
   
 Returns: Path to Construction Space containing the resource or   Returns: Path to Authoring Space containing the resource or 
          directory being viewed (or for which action is being taken).            directory being viewed (or for which action is being taken). 
          If $url is provided, and begins /priv/<domain>/<uname>           If $url is provided, and begins /priv/<domain>/<uname>
          the path will be that portion of the $context argument.           the path will be that portion of the $context argument.
Line 4668  Input: (optional) filename from which br Line 5017  Input: (optional) filename from which br
        is appropriate for use in building the breadcrumb trail.         is appropriate for use in building the breadcrumb trail.
   
 Returns: HTML div with CSTR path and recent box  Returns: HTML div with CSTR path and recent box
          To be included on Construction Space pages           To be included on Authoring Space pages
   
 =cut  =cut
   
Line 4683  sub CSTR_pageheader { Line 5032  sub CSTR_pageheader {
   
     my $londocroot = $Apache::lonnet::perlvar{'lonDocRoot'};      my $londocroot = $Apache::lonnet::perlvar{'lonDocRoot'};
     my ($udom,$uname,$thisdisfn)=      my ($udom,$uname,$thisdisfn)=
         ($trailfile =~ m{^\Q$londocroot\E/priv/([^/]+)/([^/]+)/(.*)$});          ($trailfile =~ m{^\Q$londocroot\E/priv/([^/]+)/([^/]+)(?:|/(.*))$});
     my $formaction = "/priv/$udom/$uname/$thisdisfn";      my $formaction = "/priv/$udom/$uname/$thisdisfn";
     $formaction =~ s{/+}{/}g;      $formaction =~ s{/+}{/}g;
   
Line 4699  sub CSTR_pageheader { Line 5048  sub CSTR_pageheader {
     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('Construction Space:').'</b> '          .'<b>'.&mt('Authoring Space:').'</b> '
         .'<form name="dirs" method="post" action="'.$formaction          .'<form name="dirs" method="post" action="'.$formaction
         .'" target="_top">' #FIXME lonpubdir: target="_parent"          .'" target="_top">' #FIXME lonpubdir: target="_parent"
         .&Apache::lonhtmlcommon::crumbs($uname.'/'.$parentpath,'_top','/priv/'.$udom,undef,undef);          .&Apache::lonhtmlcommon::crumbs($uname.'/'.$parentpath,'_top','/priv/'.$udom,undef,undef);
Line 4764  Inputs: Line 5113  Inputs:
                               should it have jsmath forced on by the                                should it have jsmath forced on by the
                               current page                                current page
   
   =item * $advtoolsref, optional argument, ref to an array containing
               inlineremote items to be added in "Functions" menu below
               breadcrumbs.
   
 =back  =back
   
 Returns: A uniform header for LON-CAPA web pages.    Returns: A uniform header for LON-CAPA web pages.  
Line 4775  other decorations will be returned. Line 5128  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,$args)=@_;          $no_nav_bar,$bgcolor,$args,$advtoolsref)=@_;
   
     my $public;      my $public;
     if ((($env{'user.name'} eq 'public') && ($env{'user.domain'} eq 'public'))      if ((($env{'user.name'} eq 'public') && ($env{'user.domain'} eq 'public'))
Line 4783  sub bodytag { Line 5136  sub bodytag {
         $public = 1;          $public = 1;
     }      }
     if (!$args->{'no_auto_mt_title'}) { $title = &mt($title); }      if (!$args->{'no_auto_mt_title'}) { $title = &mt($title); }
       my $httphost = $args->{'use_absolute'};
   
     $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 4798  sub bodytag { Line 5152  sub bodytag {
     @design{keys(%$addentries)} = @$addentries{keys(%$addentries)};       @design{keys(%$addentries)} = @$addentries{keys(%$addentries)}; 
   
  # role and realm   # role and realm
     my ($role,$realm) = split(/\./,$env{'request.role'},2);      my ($role,$realm) = split(m{\./},$env{'request.role'},2);
       if ($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);
Line 4824  sub bodytag { Line 5181  sub bodytag {
     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($args->{'inherit_jsmath'});
   
     if ($bodyonly) {      &get_unprocessed_cgi($ENV{'QUERY_STRING'}, ['inhibitmenu']);
   
       if (($bodyonly) || ($no_nav_bar) || ($env{'form.inhibitmenu'} eq 'yes')) {
         return $bodytag;          return $bodytag;
     }       }
   
     my $name = &plainname($env{'user.name'},$env{'user.domain'});  
     if ($public) {      if ($public) {
  undef($role);   undef($role);
     } else {  
  $name = &aboutmewrapper($name,$env{'user.name'},$env{'user.domain'});  
     }      }
           
     my $titleinfo = '<h1>'.$title.'</h1>';      my $titleinfo = '<h1>'.$title.'</h1>';
Line 4848  sub bodytag { Line 5204  sub bodytag {
     }      }
   
     $role = '<span class="LC_nobreak">('.$role.')</span>' if $role;      $role = '<span class="LC_nobreak">('.$role.')</span>' if $role;
     &get_unprocessed_cgi($ENV{'QUERY_STRING'}, ['inhibitmenu']);  
   
         if ($no_nav_bar || $env{'form.inhibitmenu'} eq 'yes') {   
             return $bodytag;   
         }   
   
         if ($env{'request.state'} eq 'construct') { $forcereg=1; }          if ($env{'request.state'} eq 'construct') { $forcereg=1; }
   
Line 4860  sub bodytag { Line 5211  sub bodytag {
         #        $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
         #    }          #    }
   
           $bodytag .= Apache::lonhtmlcommon::scripttag(
               Apache::lonmenu::utilityfunctions($httphost), 'start');
   
           my ($left,$right) = Apache::lonmenu::primary_menu();
   
         if ($env{'request.noversionuri'} =~ m{^/res/adm/pages/}) {          if ($env{'request.noversionuri'} =~ m{^/res/adm/pages/}) {
              if ($dc_info) {               if ($dc_info) {
                  $dc_info = qq|<span class="LC_cusr_subheading">$dc_info</span>|;                   $dc_info = qq|<span class="LC_cusr_subheading">$dc_info</span>|;
              }               }
              $bodytag .= qq|<div id="LC_nav_bar">$name $role<br />               $bodytag .= qq|<div id="LC_nav_bar">$left $role<br />
                 <em>$realm</em> $dc_info</div>|;                  <em>$realm</em> $dc_info</div>|;
             return $bodytag;              return $bodytag;
         }          }
   
         unless ($env{'request.symb'} =~ m/\.page___\d+___/) {          unless ($env{'request.symb'} =~ m/\.page___\d+___/) {
             $bodytag .= qq|<div id="LC_nav_bar">$name $role</div>|;              $bodytag .= qq|<div id="LC_nav_bar">$left $role</div>|;
         }          }
   
         $bodytag .= Apache::lonhtmlcommon::scripttag(          $bodytag .= $right;
             Apache::lonmenu::utilityfunctions(), 'start');  
   
         $bodytag .= Apache::lonmenu::primary_menu();  
   
         if ($dc_info) {          if ($dc_info) {
             $dc_info = &dc_courseid_toggle($dc_info);              $dc_info = &dc_courseid_toggle($dc_info);
         }          }
         $bodytag .= qq|<div id="LC_realm">$realm $dc_info</div>|;          $bodytag .= qq|<div id="LC_realm">$realm $dc_info</div>|;
   
           #if directed to not display the secondary menu, don't.  
           if ($args->{'no_secondary_menu'}) {
               return $bodytag;
           }
         #don't show menus for public users          #don't show menus for public users
         if (!$public){          if (!$public){
             $bodytag .= Apache::lonmenu::secondary_menu();              $bodytag .= Apache::lonmenu::secondary_menu($httphost);
             $bodytag .= Apache::lonmenu::serverform();              $bodytag .= Apache::lonmenu::serverform();
             $bodytag .= Apache::lonhtmlcommon::scripttag('', 'end');              $bodytag .= Apache::lonhtmlcommon::scripttag('', 'end');
             if ($env{'request.state'} eq 'construct') {              if ($env{'request.state'} eq 'construct') {
                 $bodytag .= &Apache::lonmenu::innerregister($forcereg,                  $bodytag .= &Apache::lonmenu::innerregister($forcereg,
                                 $args->{'bread_crumbs'});                                  $args->{'bread_crumbs'});
             } elsif ($forcereg) {               } elsif ($forcereg) {
                 $bodytag .= &Apache::lonmenu::innerregister($forcereg);                  $bodytag .= &Apache::lonmenu::innerregister($forcereg,undef,
                                                               $args->{'group'});
               } else {
                   $bodytag .= 
                       &Apache::lonmenu::prepare_functions($env{'request.noversionuri'},
                                                           $forcereg,$args->{'group'},
                                                           $args->{'bread_crumbs'},
                                                           $advtoolsref);
             }              }
         }else{          }else{
             # this is to seperate menu from content when there's no secondary              # this is to seperate menu from content when there's no secondary
Line 4909  sub bodytag { Line 5271  sub bodytag {
 sub dc_courseid_toggle {  sub dc_courseid_toggle {
     my ($dc_info) = @_;      my ($dc_info) = @_;
     return ' <span id="dccidtext" class="LC_cusr_subheading LC_nobreak">'.      return ' <span id="dccidtext" class="LC_cusr_subheading LC_nobreak">'.
            '<a href="javascript:showCourseID();">'.             '<a href="javascript:showCourseID();" class="LC_menubuttons_link">'.
            &mt('(More ...)').'</a></span>'.             &mt('(More ...)').'</a></span>'.
            '<div id="dccid" class="LC_dccid">'.$dc_info.'</div>';             '<div id="dccid" class="LC_dccid">'.$dc_info.'</div>';
 }  }
Line 4940  sub make_attr_string { Line 5302  sub make_attr_string {
     }      }
   
     my $attr_string;      my $attr_string;
     foreach my $attr (keys(%$attr_ref)) {      foreach my $attr (sort(keys(%$attr_ref))) {
  $attr_string .= " $attr=\"".$attr_ref->{$attr}.'" ';   $attr_string .= " $attr=\"".$attr_ref->{$attr}.'" ';
     }      }
     return $attr_string;      return $attr_string;
Line 4966  i.e., $env{'internal.head.redirect'} exi Line 5328  i.e., $env{'internal.head.redirect'} exi
   
 sub endbodytag {  sub endbodytag {
     my ($args) = @_;      my ($args) = @_;
     my $endbodytag='</body>';      my $endbodytag;
       unless ((ref($args) eq 'HASH') && ($args->{'notbody'})) {
           $endbodytag='</body>';
       }
     $endbodytag=&Apache::lontexconvert::jsMath_process()."\n".$endbodytag;      $endbodytag=&Apache::lontexconvert::jsMath_process()."\n".$endbodytag;
     if ( exists( $env{'internal.head.redirect'} ) ) {      if ( exists( $env{'internal.head.redirect'} ) ) {
         if (!(ref($args) eq 'HASH' && $args->{'noredirectlink'})) {          if (!(ref($args) eq 'HASH' && $args->{'noredirectlink'})) {
Line 5068  form, .inline { Line 5433  form, .inline {
   vertical-align:middle;    vertical-align:middle;
 }  }
   
   .LC_floatleft {
     float: left;
   }
   
   .LC_floatright {
     float: right;
   }
   
 .LC_400Box {  .LC_400Box {
   width:400px;    width:400px;
 }  }
Line 5106  form, .inline { Line 5479  form, .inline {
   
 .LC_error {  .LC_error {
   color: red;    color: red;
   font-size: larger;  
 }  }
   
 .LC_warning,  .LC_warning {
     color: darkorange;
   }
   
 .LC_diff_removed {  .LC_diff_removed {
   color: red;    color: red;
 }  }
Line 5272  td.LC_table_cell_checkbox { Line 5647  td.LC_table_cell_checkbox {
   text-align: left;    text-align: left;
 }  }
   
 .LC_head_subbox {  .LC_head_subbox, .LC_actionbox {
   clear:both;    clear:both;
   background: #F8F8F8; /* $sidebg; */    background: #F8F8F8; /* $sidebg; */
   border: 1px solid $sidebg;    border: 1px solid $sidebg;
   margin: 0 0 10px 0;          margin: 0 0 10px 0;
   padding: 3px;    padding: 3px;
   text-align: left;    text-align: left;
 }  }
Line 5409  table.LC_nested tr.LC_empty_row td { Line 5784  table.LC_nested tr.LC_empty_row td {
   padding: 8px;    padding: 8px;
 }  }
   
 table.LC_data_table tr.LC_empty_row td {  table.LC_data_table tr.LC_empty_row td,
   table.LC_data_table tr.LC_footer_row td {
   background-color: $sidebg;    background-color: $sidebg;
 }  }
   
Line 5971  div.LC_docs_entry_move { Line 6347  div.LC_docs_entry_move {
   
 table.LC_data_table tr > td.LC_docs_entry_commands,  table.LC_data_table tr > td.LC_docs_entry_commands,
 table.LC_data_table tr > td.LC_docs_entry_parameter {  table.LC_data_table tr > td.LC_docs_entry_parameter {
   background: #DDDDDD;  
   font-size: x-small;    font-size: x-small;
 }  }
   
Line 6136  div.LC_edit_problem_saves { Line 6511  div.LC_edit_problem_saves {
   padding-bottom: 5px;    padding-bottom: 5px;
 }  }
   
   .LC_edit_opt {
     padding-left: 1em;
     white-space: nowrap;
   }
   
   .LC_edit_problem_latexhelper{
       text-align: right;
   }
   
   #LC_edit_problem_colorful div{
       margin-left: 40px;
   }
   
 img.stift {  img.stift {
   border-width: 0;    border-width: 0;
   vertical-align: middle;    vertical-align: middle;
Line 6150  div.LC_createcourse { Line 6538  div.LC_createcourse {
 }  }
   
 .LC_dccid {  .LC_dccid {
     float: right;
   margin: 0.2em 0 0 0;    margin: 0.2em 0 0 0;
   padding: 0;    padding: 0;
   font-size: 90%;    font-size: 90%;
Line 6247  fieldset > legend { Line 6636  fieldset > legend {
 }  }
   
 ol.LC_primary_menu {  ol.LC_primary_menu {
   float: right;  
   margin: 0;    margin: 0;
     padding: 0;
   background-color: $pgbg_or_bgcolor;    background-color: $pgbg_or_bgcolor;
 }  }
   
Line 6257  ol#LC_PathBreadcrumbs { Line 6646  ol#LC_PathBreadcrumbs {
 }  }
   
 ol.LC_primary_menu li {  ol.LC_primary_menu li {
   display: inline;    color: RGB(80, 80, 80);
   padding: 5px 5px 0 10px;    vertical-align: middle;
     text-align: left;
     list-style: none;
     float: left;
   }
   
   ol.LC_primary_menu li a {
     display: block;
     margin: 0;
     padding: 0 5px 0 10px;
     text-decoration: none;
   }
   
   ol.LC_primary_menu li ul {
     display: none;
     width: 10em;
     background-color: $data_table_light;
   }
   
   ol.LC_primary_menu li:hover ul, ol.LC_primary_menu li.hover ul {
     display: block;
     position: absolute;
     margin: 0;
     padding: 0;
     z-index: 2;
   }
   
   ol.LC_primary_menu li:hover li, ol.LC_primary_menu li.hover li {
     font-size: 90%;
   vertical-align: top;    vertical-align: top;
     float: none;
     border-left: 1px solid black;
     border-right: 1px solid black;
   }
   
   ol.LC_primary_menu li:hover li a, ol.LC_primary_menu li.hover li a {
     background-color:$data_table_light;
   }
   
   ol.LC_primary_menu li li a:hover {
      color:$button_hover;
      background-color:$data_table_dark;
 }  }
   
 ol.LC_primary_menu li img {  ol.LC_primary_menu li img {
   vertical-align: bottom;    vertical-align: bottom;
   height: 1.1em;    height: 1.1em;
     margin: 0.2em 0 0 0;
 }  }
   
 ol.LC_primary_menu a {  ol.LC_primary_menu a {
Line 6302  ol.LC_docs_parameters li.LC_docs_paramet Line 6732  ol.LC_docs_parameters li.LC_docs_paramet
 }  }
   
 ul#LC_secondary_menu {  ul#LC_secondary_menu {
   clear: both;    clear: right;
   color: $fontmenu;    color: $fontmenu;
   background: $tabbg;    background: $tabbg;
   list-style: none;    list-style: none;
Line 6310  ul#LC_secondary_menu { Line 6740  ul#LC_secondary_menu {
   margin: 0;    margin: 0;
   width: 100%;    width: 100%;
   text-align: left;    text-align: left;
     float: left;
 }  }
   
 ul#LC_secondary_menu li {  ul#LC_secondary_menu li {
   font-weight: bold;    font-weight: bold;
   line-height: 1.8em;    line-height: 1.8em;
     border-right: 1px solid black;
     float: left;
   }
   
   ul#LC_secondary_menu li.LC_hoverable:hover, ul#LC_secondary_menu li.hover {
     background-color: $data_table_light;
   }
   
   ul#LC_secondary_menu li a {
   padding: 0 0.8em;    padding: 0 0.8em;
   }
   
   ul#LC_secondary_menu li ul {
     display: none;
   }
   
   ul#LC_secondary_menu li:hover ul, ul#LC_secondary_menu li.hover ul {
     display: block;
     position: absolute;
     margin: 0;
     padding: 0;
     list-style:none;
     float: none;
     background-color: $data_table_light;
     z-index: 2;
     margin-left: -1px;
   }
   
   ul#LC_secondary_menu li ul li {
     font-size: 90%;
     vertical-align: top;
     border-left: 1px solid black;
   border-right: 1px solid black;    border-right: 1px solid black;
   display: inline;    background-color: $data_table_light;
   vertical-align: middle;    list-style:none;
     float: none;
   }
   
   ul#LC_secondary_menu li ul li:hover, ul#LC_secondary_menu li ul li.hover {
     background-color: $data_table_dark;
 }  }
   
 ul.LC_TabContent {  ul.LC_TabContent {
Line 6658  ul#LC_toolbar { Line 7125  ul#LC_toolbar {
   list-style:none;    list-style:none;
   position:relative;    position:relative;
   background-color:white;    background-color:white;
     overflow: auto;
 }  }
   
 ul#LC_toolbar li {  ul#LC_toolbar li {
Line 6667  ul#LC_toolbar li { Line 7135  ul#LC_toolbar li {
   float: left;    float: left;
   display:inline;    display:inline;
   vertical-align:middle;    vertical-align:middle;
     white-space: nowrap;
 }  }
   
   
Line 6763  ul.LC_funclist li { Line 7232  ul.LC_funclist li {
  cursor:pointer;   cursor:pointer;
 }  }
   
   /*
     styles used by TTH when "Default set of options to pass to tth/m
     when converting TeX" in course settings has been set
   
     option passed: -t
   
   */
   
   td div.comp { margin-top: -0.6ex; margin-bottom: -1ex;}
   td div.comb { margin-top: -0.6ex; margin-bottom: -.6ex;}
   td div.hrcomp { line-height: 0.9; margin-top: -0.8ex; margin-bottom: -1ex;}
   td div.norm {line-height:normal;}
   
   /*
     option passed -y3
   */
   
   span.roman {font-family: serif; font-style: normal; font-weight: normal;}
   span.overacc2 {position: relative;  left: .8em; top: -1.2ex;}
   span.overacc1 {position: relative;  left: .6em; top: -1.2ex;}
   
 END  END
 }  }
   
Line 6799  sub headtag { Line 7289  sub headtag {
     my $function = $args->{'function'} || &get_users_function();      my $function = $args->{'function'} || &get_users_function();
     my $domain   = $args->{'domain'}   || &determinedomain();      my $domain   = $args->{'domain'}   || &determinedomain();
     my $bgcolor  = $args->{'bgcolor'}  || &designparm($function.'.pgbg',$domain);      my $bgcolor  = $args->{'bgcolor'}  || &designparm($function.'.pgbg',$domain);
       my $httphost = $args->{'use_absolute'};
     my $url = join(':',$env{'user.name'},$env{'user.domain'},      my $url = join(':',$env{'user.name'},$env{'user.domain'},
    $Apache::lonnet::perlvar{'lonVersion'},     $Apache::lonnet::perlvar{'lonVersion'},
    #time(),     #time(),
Line 6809  sub headtag { Line 7300  sub headtag {
   
     my $result =      my $result =
  '<head>'.   '<head>'.
  &font_settings();   &font_settings($args);
   
       my $inhibitprint = &print_suppression();
   
     if (!$args->{'frameset'}) {      if (!$args->{'frameset'}) {
  $result .= &Apache::lonhtmlcommon::htmlareaheaders();   $result .= &Apache::lonhtmlcommon::htmlareaheaders();
Line 6820  sub headtag { Line 7313  sub headtag {
     if (!$args->{'no_nav_bar'}       if (!$args->{'no_nav_bar'} 
  && !$args->{'only_body'}   && !$args->{'only_body'}
  && !$args->{'frameset'}) {   && !$args->{'frameset'}) {
  $result .= &help_menu_js();   $result .= &help_menu_js($httphost);
         $result.=&modal_window();          $result.=&modal_window();
         $result.=&togglebox_script();          $result.=&togglebox_script();
         $result.=&wishlist_window();          $result.=&wishlist_window();
Line 6855  ADDMETA Line 7348  ADDMETA
     }      }
     if (!$args->{'no_auto_mt_title'}) { $title = &mt($title); }      if (!$args->{'no_auto_mt_title'}) { $title = &mt($title); }
     $result .= '<title> LON-CAPA '.$title.'</title>'      $result .= '<title> LON-CAPA '.$title.'</title>'
  .'<link rel="stylesheet" type="text/css" href="'.$url.'" />'   .'<link rel="stylesheet" type="text/css" href="'.$url.'"';
       if (!$args->{'frameset'}) {
           $result .= ' /';
       }
       $result .= '>' 
           .$inhibitprint
  .$head_extra;   .$head_extra;
       if ($env{'browser.mobile'}) {
           $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="apple-mobile-web-app-capable" content="yes" />';
       }
     return $result.'</head>';      return $result.'</head>';
 }  }
   
Line 6866  ADDMETA Line 7369  ADDMETA
   
 Returns neccessary <meta> to set the proper encoding  Returns neccessary <meta> to set the proper encoding
   
 Inputs: none  Inputs: optional reference to HASH -- $args passed to &headtag()
   
 =cut  =cut
   
 sub font_settings {  sub font_settings {
       my ($args) = @_;
     my $headerstring='';      my $headerstring='';
     if (!$env{'browser.mathml'} && $env{'browser.unicode'}) {      if ((!$env{'browser.mathml'} && $env{'browser.unicode'}) ||
  $headerstring.=          ((ref($args) eq 'HASH') && ($args->{'browser.unicode'}))) {
     '<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />';          $headerstring.=
               '<meta http-equiv="Content-Type" content="text/html; charset=utf-8"';
           if (!$args->{'frameset'}) {
       $headerstring.= ' /';
           }
    $headerstring .= '>'."\n";
     }      }
     return $headerstring;      return $headerstring;
 }  }
   
 =pod  =pod
   
   =item * &print_suppression()
   
   In course context returns css which causes the body to be blank when media="print",
   if printout generation is unavailable for the current resource.
   
   This could be because:
   
   (a) printstartdate is in the future
   
   (b) printenddate is in the past
   
   (c) there is an active exam block with "printout"
   functionality blocked
   
   Users with pav, pfo or evb privileges are exempt.
   
   Inputs: none
   
   =cut
   
   
   sub print_suppression {
       my $noprint;
       if ($env{'request.course.id'}) {
           my $scope = $env{'request.course.id'};
           if ((&Apache::lonnet::allowed('pav',$scope)) ||
               (&Apache::lonnet::allowed('pfo',$scope))) {
               return;
           }
           if ($env{'request.course.sec'} ne '') {
               $scope .= "/$env{'request.course.sec'}";
               if ((&Apache::lonnet::allowed('pav',$scope)) ||
                   (&Apache::lonnet::allowed('pfo',$scope))) {
                   return;
               }
           }
           my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
           my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
           my $blocked = &blocking_status('printout',$cnum,$cdom);
           if ($blocked) {
               my $checkrole = "cm./$cdom/$cnum";
               if ($env{'request.course.sec'} ne '') {
                   $checkrole .= "/$env{'request.course.sec'}";
               }
               unless ((&Apache::lonnet::allowed('evb',undef,undef,$checkrole)) &&
                       ($env{'request.role'} !~ m{^st\./$cdom/$cnum})) {
                   $noprint = 1;
               }
           }
           unless ($noprint) {
               my $symb = &Apache::lonnet::symbread();
               if ($symb ne '') {
                   my $navmap = Apache::lonnavmaps::navmap->new();
                   if (ref($navmap)) {
                       my $res = $navmap->getBySymb($symb);
                       if (ref($res)) {
                           if (!$res->resprintable()) {
                               $noprint = 1;
                           }
                       }
                   }
               }
           }
           if ($noprint) {
               return <<"ENDSTYLE";
   <style type="text/css" media="print">
       body { display:none }
   </style>
   ENDSTYLE
           }
       }
       return;
   }
   
   =pod
   
 =item * &xml_begin()  =item * &xml_begin()
   
 Returns the needed doctype and <html>  Returns the needed doctype and <html>
Line 6890  Inputs: none Line 7475  Inputs: none
 =cut  =cut
   
 sub xml_begin {  sub xml_begin {
       my ($is_frameset) = @_;
     my $output='';      my $output='';
   
     if ($env{'browser.mathml'}) {      if ($env{'browser.mathml'}) {
Line 6901  sub xml_begin { Line 7487  sub xml_begin {
     .'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1 plus MathML 2.0 plus SVG 1.1//EN" "http://www.w3.org/2002/04/xhtml-math-svg/xhtml-math-svg.dtd">'      .'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1 plus MathML 2.0 plus SVG 1.1//EN" "http://www.w3.org/2002/04/xhtml-math-svg/xhtml-math-svg.dtd">'
             .'<html xmlns:math="http://www.w3.org/1998/Math/MathML" '               .'<html xmlns:math="http://www.w3.org/1998/Math/MathML" ' 
     .'xmlns="http://www.w3.org/1999/xhtml">';      .'xmlns="http://www.w3.org/1999/xhtml">';
       } elsif ($is_frameset) {
           $output='<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">'."\n".
                   '<html>'."\n";
     } else {      } else {
  $output='<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">'   $output='<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">'."\n".
            .'<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">';                  '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">'."\n";
     }      }
     return $output;      return $output;
 }  }
Line 6953  $args - additional optional args support Line 7542  $args - additional optional args support
                                     current page                                      current page
              bread_crumbs ->             Array containing breadcrumbs               bread_crumbs ->             Array containing breadcrumbs
              bread_crumbs_component ->  if exists show it as headline else show only the breadcrumbs               bread_crumbs_component ->  if exists show it as headline else show only the breadcrumbs
                group          -> includes the current group, if page is for a 
                                  specific group  
   
 =back  =back
   
Line 6965  sub start_page { Line 7556  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;      my ($result,@advtools);
   
     if (! exists($args->{'skip_phases'}{'head'}) ) {      if (! exists($args->{'skip_phases'}{'head'}) ) {
         $result .= &xml_begin() . &headtag($title, $head_extra, $args);          $result .= &xml_begin($args->{'frameset'}) . &headtag($title, $head_extra, $args);
     }      }
           
     if (! exists($args->{'skip_phases'}{'body'}) ) {      if (! exists($args->{'skip_phases'}{'body'}) ) {
Line 6982  sub start_page { Line 7573  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);                           $args->{'bgcolor'},        $args,
                            \@advtools);
         }          }
     }      }
   
Line 7011  sub start_page { Line 7603  sub start_page {
  &Apache::lonhtmlcommon::add_breadcrumb($crumb);   &Apache::lonhtmlcommon::add_breadcrumb($crumb);
  }   }
  }   }
                   # if @advtools array contains items add then to the breadcrumbs
                   if (@advtools > 0) {
                       &Apache::lonmenu::advtools_crumbs(@advtools);
                   }
   
  #if bread_crumbs_component exists show it as headline else show only the breadcrumbs   #if bread_crumbs_component exists show it as headline else show only the breadcrumbs
  if(exists($args->{'bread_crumbs_component'})){   if(exists($args->{'bread_crumbs_component'})){
Line 7039  sub end_page { Line 7635  sub end_page {
     } else {      } else {
  $result .= &endbodytag($args);   $result .= &endbodytag($args);
     }      }
     $result .= "\n</html>";      unless ($args->{'notbody'}) {
           $result .= "\n</html>";
       }
   
     if ($args->{'js_ready'}) {      if ($args->{'js_ready'}) {
  $result = &js_ready($result);   $result = &js_ready($result);
Line 7062  function set_wishlistlink(title, path) { Line 7660  function set_wishlistlink(title, path) {
         title = document.title;          title = document.title;
         title = title.replace(/^LON-CAPA /,'');          title = title.replace(/^LON-CAPA /,'');
     }      }
       title = encodeURIComponent(title);
     if (!path) {      if (!path) {
         path = location.pathname;          path = location.pathname;
     }      }
       path = encodeURIComponent(path);
     Win = window.open('/adm/wishlist?mode=newLink&setTitle='+title+'&setPath='+path,      Win = window.open('/adm/wishlist?mode=newLink&setTitle='+title+'&setPath='+path,
                       'wishlistNewLink','width=560,height=350,scrollbars=0');                        'wishlistNewLink','width=560,height=350,scrollbars=0');
 }  }
Line 7105  var modalWindow = { Line 7705  var modalWindow = {
  $(".LCmodal-overlay").click(function(){modalWindow.close();});   $(".LCmodal-overlay").click(function(){modalWindow.close();});
  }   }
 };  };
  var openMyModal = function(source,width,height,scrolling)   var openMyModal = function(source,width,height,scrolling,transparency,style)
  {   {
  modalWindow.windowId = "myModal";   modalWindow.windowId = "myModal";
  modalWindow.width = width;   modalWindow.width = width;
  modalWindow.height = height;   modalWindow.height = height;
  modalWindow.content = "<iframe width='"+width+"' height='"+height+"' frameborder='0' scrolling='"+scrolling+"' allowtransparency='true' src='" + source + "'>&lt/iframe>";   modalWindow.content = "<iframe width='"+width+"' height='"+height+"' frameborder='0' scrolling='"+scrolling+"' allowtransparency='"+transparency+"' src='" + source + "' style='"+style+"'>&lt/iframe>";
  modalWindow.open();   modalWindow.open();
  };   };
 // END LON-CAPA Internal -->  // END LON-CAPA Internal -->
Line 7120  ENDMODAL Line 7720  ENDMODAL
 }  }
   
 sub modal_link {  sub modal_link {
     my ($link,$linktext,$width,$height,$target,$scrolling,$title)=@_;      my ($link,$linktext,$width,$height,$target,$scrolling,$title,$transparency,$style)=@_;
     unless ($width) { $width=480; }      unless ($width) { $width=480; }
     unless ($height) { $height=400; }      unless ($height) { $height=400; }
     unless ($scrolling) { $scrolling='yes'; }      unless ($scrolling) { $scrolling='yes'; }
     return '<a href="'.$link.'" target="'.$target.'" title="'.$title.'" onclick="openMyModal(\''.$link.'\','.$width.','.$height.',\''.$scrolling.'\'); return false;">'.      unless ($transparency) { $transparency='true'; }
            $linktext.'</a>';  
       my $target_attr;
       if (defined($target)) {
           $target_attr = 'target="'.$target.'"';
       }
       return <<"ENDLINK";
   <a href="$link" $target_attr title="$title" onclick="javascript:openMyModal('$link',$width,$height,'$scrolling','$transparency','$style'); return false;">
              $linktext</a>
   ENDLINK
 }  }
   
 sub modal_adhoc_script {  sub modal_adhoc_script {
Line 7150  sub modal_adhoc_inner { Line 7758  sub modal_adhoc_inner {
     my ($funcname,$width,$height,$content)=@_;      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').                   &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);      return &modal_adhoc_script($funcname,$width,$height,$content);
 }  }
Line 7273  sub LCprogressbar { Line 7881  sub LCprogressbar {
     $LCcurrentid=$$.'_'.$LCidcnt;      $LCcurrentid=$$.'_'.$LCidcnt;
     my $starting=&mt('Starting');      my $starting=&mt('Starting');
     my $content=(<<ENDPROGBAR);      my $content=(<<ENDPROGBAR);
 <p>  
   <div id="progressbar$LCcurrentid">    <div id="progressbar$LCcurrentid">
     <span class="pblabel">$starting</span>      <span class="pblabel">$starting</span>
   </div>    </div>
 </p>  
 ENDPROGBAR  ENDPROGBAR
     &r_print($r,$content.&LCprogressbar_script($LCcurrentid));      &r_print($r,$content.&LCprogressbar_script($LCcurrentid));
 }  }
Line 7373  sub validate_page { Line 7979  sub validate_page {
   
   
 sub start_scrollbox {  sub start_scrollbox {
     my ($outerwidth,$width,$height,$id)=@_;      my ($outerwidth,$width,$height,$id,$bgcolor,$cursor,$needjsready) = @_;
     unless ($outerwidth) { $outerwidth='520px'; }      unless ($outerwidth) { $outerwidth='520px'; }
     unless ($width) { $width='500px'; }      unless ($width) { $width='500px'; }
     unless ($height) { $height='200px'; }      unless ($height) { $height='200px'; }
     my ($table_id,$div_id);      my ($table_id,$div_id,$tdcol);
     if ($id ne '') {      if ($id ne '') {
         $table_id = " id='table_$id'";          $table_id = ' id="table_'.$id.'"';
         $div_id = " id='div_$id'";          $div_id = ' id="div_'.$id.'"';
       }
       if ($bgcolor ne '') {
           $tdcol = "background-color: $bgcolor;";
       }
       my $nicescroll_js;
       if ($env{'browser.mobile'}) {
           $nicescroll_js = &nicescroll_javascript('div_'.$id,$cursor,$needjsready);
     }      }
     return "<table style='width: $outerwidth; border: 1px solid none;'$table_id><tr><td style='width: $width;' bgcolor='#FFFFFF'><div style='overflow:auto; width:$width; height: $height;'$div_id>";      return <<"END";
   $nicescroll_js
   
   <table style="width: $outerwidth; border: 1px solid none;"$table_id><tr><td style="width: $width;$tdcol">
   <div style="overflow:auto; width:$width; height:$height;"$div_id>
   END
 }  }
   
 sub end_scrollbox {  sub end_scrollbox {
     return '</div></td></tr></table>';      return '</div></td></tr></table>';
 }  }
   
   sub nicescroll_javascript {
       my ($id,$cursor,$needjsready,$framecheck,$location) = @_;
       my %options;
       if (ref($cursor) eq 'HASH') {
           %options = %{$cursor};
       }
       unless ($options{'railalign'} =~ /^left|right$/) {
           $options{'railalign'} = 'left';
       }
       unless ($options{'cursorcolor'} =~ /^\#\w+$/) {
           my $function  = &get_users_function();
           $options{'cursorcolor'} = &designparm($function.'.sidebg',$env{'request.role.domain'});
           unless ($options{'cursorcolor'} =~ /^\#\w+$/) {
               $options{'cursorcolor'} = '#00F';
           }
       }
       if ($options{'cursoropacity'} =~ /^[\d.]+$/) {
           unless ($options{'cursoropacity'} >= 0.0 && $options{'cursoropacity'} <=1.0) {
               $options{'cursoropacity'}='1.0';
           }
       } else {
           $options{'cursoropacity'}='1.0';
       }
       if ($options{'cursorfixedheight'} eq 'none') {
           delete($options{'cursorfixedheight'});
       } else {
           unless ($options{'cursorfixedheight'} =~ /^\d+$/) { $options{'cursorfixedheight'}='50'; }
       }
       unless ($options{'railoffset'} =~ /^{[\w\:\d\-,]+}$/) {
           delete($options{'railoffset'});
       }
       my @niceoptions;
       while (my($key,$value) = each(%options)) {
           if ($value =~ /^\{.+\}$/) {
               push(@niceoptions,$key.':'.$value);
           } else {
               push(@niceoptions,$key.':"'.$value.'"');
           }
       }
       my $nicescroll_js = '
   $(document).ready(
         function() {
             $("#'.$id.'").niceScroll({'.join(',',@niceoptions).'});
         }
   );
   ';
       if ($framecheck) {
           $nicescroll_js .= '
   function expand_div(caller) {
       if (top === self) {
           document.getElementById("'.$id.'").style.width = "auto";
           document.getElementById("'.$id.'").style.height = "auto";
       } else {
           try {
               if (parent.frames) {
                   if (parent.frames.length > 1) {
                       var framesrc = parent.frames[1].location.href;
                       var currsrc = framesrc.replace(/\#.*$/,"");
                       if ((caller == "search") || (currsrc == "'.$location.'")) {
                           document.getElementById("'.$id.'").style.width = "auto";
                           document.getElementById("'.$id.'").style.height = "auto";
                       }
                   }
               }
           } catch (e) {
               return;
           }
       }
       return;
   }
   ';
       }
       if ($needjsready) {
           $nicescroll_js = '
   <script type="text/javascript">'."\n".$nicescroll_js."\n</script>\n";
       } else {
           $nicescroll_js = &Apache::lonhtmlcommon::scripttag($nicescroll_js);
       }
       return $nicescroll_js;
   }
   
 sub simple_error_page {  sub simple_error_page {
     my ($r,$title,$msg) = @_;      my ($r,$title,$msg,$args) = @_;
       if (ref($args) eq 'HASH') {
           if (!$args->{'no_auto_mt_msg'}) { $msg = &mt($msg); }
       } else {
           $msg = &mt($msg);
       }
   
     my $page =      my $page =
  &Apache::loncommon::start_page($title).   &Apache::loncommon::start_page($title).
  &mt($msg).   '<p class="LC_error">'.$msg.'</p>'.
  &Apache::loncommon::end_page();   &Apache::loncommon::end_page();
     if (ref($r)) {      if (ref($r)) {
  $r->print($page);   $r->print($page);
Line 7608  role status: active, previous or future. Line 8313  role status: active, previous or future.
   
 sub check_user_status {  sub check_user_status {
     my ($udom,$uname,$cdom,$crs,$role,$sec) = @_;      my ($udom,$uname,$cdom,$crs,$role,$sec) = @_;
     my $extra = &Apache::lonnet::freeze_escape({'skipcheck' => 1});      my %userinfo = &Apache::lonnet::dump('roles',$udom,$uname);
     my %userinfo = &Apache::lonnet::dump('roles',$udom,$uname,'.',undef,$extra);  
     my @uroles = keys %userinfo;      my @uroles = keys %userinfo;
     my $srchstr;      my $srchstr;
     my $active_chk = 'none';      my $active_chk = 'none';
Line 7687  sub get_sections { Line 8391  sub get_sections {
     my %sectioncount;      my %sectioncount;
     my $now = time;      my $now = time;
   
     if (!defined($possible_roles) || (grep(/^st$/,@$possible_roles))) {      my $check_students = 1;
       my $only_students = 0;
       if (ref($possible_roles) eq 'ARRAY') {
           if (grep(/^st$/,@{$possible_roles})) {
               if (@{$possible_roles} == 1) {
                   $only_students = 1;
               }
           } else {
               $check_students = 0;
           }
       }
   
       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 7714  sub get_sections { Line 8430  sub get_sections {
     }      }
  }   }
     }      }
       if ($only_students) {
           return %sectioncount;
       }
     my %courseroles = &Apache::lonnet::dump('nohist_userroles',$cdom,$cnum);      my %courseroles = &Apache::lonnet::dump('nohist_userroles',$cdom,$cnum);
     foreach my $user (sort(keys(%courseroles))) {      foreach my $user (sort(keys(%courseroles))) {
  if ($user !~ /^(\w{2})/) { next; }   if ($user !~ /^(\w{2})/) { next; }
Line 7861  sub get_course_users { Line 8580  sub get_course_users {
                               active   => 'Active',                                active   => 'Active',
                               future   => 'Future',                                future   => 'Future',
                             );                              );
         my %nothide;          my (%nothide,@possdoms);
         if ($hidepriv) {          if ($hidepriv) {
             my %coursehash=&Apache::lonnet::coursedescription($cdom.'_'.$cnum);              my %coursehash=&Apache::lonnet::coursedescription($cdom.'_'.$cnum);
             foreach my $user (split(/\s*\,\s*/,$coursehash{'nothideprivileged'})) {              foreach my $user (split(/\s*\,\s*/,$coursehash{'nothideprivileged'})) {
Line 7871  sub get_course_users { Line 8590  sub get_course_users {
                     $nothide{$user} = 1;                      $nothide{$user} = 1;
                 }                  }
             }              }
               my @possdoms = ($cdom);
               if ($coursehash{'checkforpriv'}) {
                   push(@possdoms,split(/,/,$coursehash{'checkforpriv'}));
               }
         }          }
         foreach my $person (sort(keys(%coursepersonnel))) {          foreach my $person (sort(keys(%coursepersonnel))) {
             my $match = 0;              my $match = 0;
Line 7906  sub get_course_users { Line 8629  sub get_course_users {
                 }                  }
                 if ($uname ne '' && $udom ne '') {                  if ($uname ne '' && $udom ne '') {
                     if ($hidepriv) {                      if ($hidepriv) {
                         if ((&Apache::lonnet::privileged($uname,$udom)) &&                          if ((&Apache::lonnet::privileged($uname,$udom,\@possdoms)) &&
                             (!$nothide{$uname.':'.$udom})) {                              (!$nothide{$uname.':'.$udom})) {
                             next;                              next;
                         }                          }
Line 7994  sub get_user_info { Line 8717  sub get_user_info {
   
 =item * &get_user_quota()  =item * &get_user_quota()
   
 Retrieves quota assigned for storage of portfolio files for a user    Retrieves quota assigned for storage of user files.
   Default is to report quota for portfolio files.
   
 Incoming parameters:  Incoming parameters:
 1. user's username  1. user's username
 2. user's domain  2. user's domain
   3. quota name - portfolio, author, or course
      (if no quota name provided, defaults to portfolio).
   4. crstype - official, unofficial, textbook or community, if quota name is
      course
   
 Returns:  Returns:
 1. Disk quota (in Mb) assigned to student.  1. Disk quota (in MB) assigned to student.
 2. (Optional) Type of setting: custom or default  2. (Optional) Type of setting: custom or default
    (individually assigned or default for user's      (individually assigned or default for user's 
    institutional status).     institutional status).
Line 8012  Returns: Line 8740  Returns:
   
 If a value has been stored in the user's environment,   If a value has been stored in the user's environment, 
 it will return that, otherwise it returns the maximal default  it will return that, otherwise it returns the maximal default
 defined for the user's instituional status(es) in the domain.  defined for the user's institutional status(es) in the domain.
   
 =cut  =cut
   
Line 8020  defined for the user's instituional stat Line 8748  defined for the user's instituional stat
   
   
 sub get_user_quota {  sub get_user_quota {
     my ($uname,$udom) = @_;      my ($uname,$udom,$quotaname,$crstype) = @_;
     my ($quota,$quotatype,$settingstatus,$defquota);      my ($quota,$quotatype,$settingstatus,$defquota);
     if (!defined($udom)) {      if (!defined($udom)) {
         $udom = $env{'user.domain'};          $udom = $env{'user.domain'};
Line 8035  sub get_user_quota { Line 8763  sub get_user_quota {
         $defquota = 0;           $defquota = 0; 
     } else {      } else {
         my $inststatus;          my $inststatus;
         if ($udom eq $env{'user.domain'} && $uname eq $env{'user.name'}) {          if ($quotaname eq 'course') {
             $quota = $env{'environment.portfolioquota'};              if (($env{'course.'.$udom.'_'.$uname.'.num'} eq $uname) &&
             $inststatus = $env{'environment.inststatus'};                  ($env{'course.'.$udom.'_'.$uname.'.domain'} eq $udom)) {
         } else {                  $quota = $env{'course.'.$udom.'_'.$uname.'.internal.uploadquota'};
             my %userenv =               } else {
                 &Apache::lonnet::get('environment',['portfolioquota',                  my %cenv = &Apache::lonnet::coursedescription("$udom/$uname");
                                      'inststatus'],$udom,$uname);                  $quota = $cenv{'internal.uploadquota'};
             my ($tmp) = keys(%userenv);              }
             if ($tmp !~ /^(con_lost|error|no_such_host)/i) {  
                 $quota = $userenv{'portfolioquota'};  
                 $inststatus = $userenv{'inststatus'};  
             } else {  
                 undef(%userenv);  
             }  
         }  
         ($defquota,$settingstatus) = &default_quota($udom,$inststatus);  
         if ($quota eq '') {  
             $quota = $defquota;  
             $quotatype = 'default';  
         } else {          } else {
             $quotatype = 'custom';              if ($udom eq $env{'user.domain'} && $uname eq $env{'user.name'}) {
                   if ($quotaname eq 'author') {
                       $quota = $env{'environment.authorquota'};
                   } else {
                       $quota = $env{'environment.portfolioquota'};
                   }
                   $inststatus = $env{'environment.inststatus'};
               } else {
                   my %userenv = 
                       &Apache::lonnet::get('environment',['portfolioquota',
                                            'authorquota','inststatus'],$udom,$uname);
                   my ($tmp) = keys(%userenv);
                   if ($tmp !~ /^(con_lost|error|no_such_host)/i) {
                       if ($quotaname eq 'author') {
                           $quota = $userenv{'authorquota'};
                       } else {
                           $quota = $userenv{'portfolioquota'};
                       }
                       $inststatus = $userenv{'inststatus'};
                   } else {
                       undef(%userenv);
                   }
               }
           }
           if ($quota eq '' || wantarray) {
               if ($quotaname eq 'course') {
                   my %domdefs = &Apache::lonnet::get_domain_defaults($udom);
                   if (($crstype eq 'official') || ($crstype eq 'unofficial') || 
                       ($crstype eq 'community') || ($crstype eq 'textbook')) { 
                       $defquota = $domdefs{$crstype.'quota'};
                   }
                   if ($defquota eq '') {
                       $defquota = 500;
                   }
               } else {
                   ($defquota,$settingstatus) = &default_quota($udom,$inststatus,$quotaname);
               }
               if ($quota eq '') {
                   $quota = $defquota;
                   $quotatype = 'default';
               } else {
                   $quotatype = 'custom';
               }
         }          }
     }      }
     if (wantarray) {      if (wantarray) {
Line 8075  Retrieves default quota assigned for sto Line 8834  Retrieves default quota assigned for sto
 given an (optional) user's institutional status.  given an (optional) user's institutional status.
   
 Incoming parameters:  Incoming parameters:
   
 1. domain  1. domain
 2. (Optional) institutional status(es).  This is a : separated list of   2. (Optional) institutional status(es).  This is a : separated list of 
    status types (e.g., faculty, staff, student etc.)     status types (e.g., faculty, staff, student etc.)
    which apply to the user for whom the default is being retrieved.     which apply to the user for whom the default is being retrieved.
    If the institutional status string in undefined, the domain     If the institutional status string in undefined, the domain
    default quota will be returned.      default quota will be returned.
   3.  quota name - portfolio, author, or course
      (if no quota name provided, defaults to portfolio).
   
 Returns:  Returns:
 1. Default disk quota (in Mb) for user portfolios in the domain.  
   1. Default disk quota (in MB) for user portfolios in the domain.
 2. (Optional) institutional type which determined the value of the  2. (Optional) institutional type which determined the value of the
    default quota.     default quota.
   
 If a value has been stored in the domain's configuration db,  If a value has been stored in the domain's configuration db,
 it will return that, otherwise it returns 20 (for backwards   it will return that, otherwise it returns 20 (for backwards 
 compatibility with domains which have not set up a configuration  compatibility with domains which have not set up a configuration
 db file; the original statically defined portfolio quota was 20 Mb).   db file; the original statically defined portfolio quota was 20 MB). 
   
 If the user's status includes multiple types (e.g., staff and student),  If the user's status includes multiple types (e.g., staff and student),
 the largest default quota which applies to the user determines the  the largest default quota which applies to the user determines the
 default quota returned.  default quota returned.
   
 =back  
   
 =cut  =cut
   
 ###############################################  ###############################################
   
   
 sub default_quota {  sub default_quota {
     my ($udom,$inststatus) = @_;      my ($udom,$inststatus,$quotaname) = @_;
     my ($defquota,$settingstatus);      my ($defquota,$settingstatus);
     my %quotahash = &Apache::lonnet::get_dom('configuration',      my %quotahash = &Apache::lonnet::get_dom('configuration',
                                             ['quotas'],$udom);                                              ['quotas'],$udom);
       my $key = 'defaultquota';
       if ($quotaname eq 'author') {
           $key = 'authorquota';
       }
     if (ref($quotahash{'quotas'}) eq 'HASH') {      if (ref($quotahash{'quotas'}) eq 'HASH') {
         if ($inststatus ne '') {          if ($inststatus ne '') {
             my @statuses = map { &unescape($_); } split(/:/,$inststatus);              my @statuses = map { &unescape($_); } split(/:/,$inststatus);
             foreach my $item (@statuses) {              foreach my $item (@statuses) {
                 if (ref($quotahash{'quotas'}{'defaultquota'}) eq 'HASH') {                  if (ref($quotahash{'quotas'}{$key}) eq 'HASH') {
                     if ($quotahash{'quotas'}{'defaultquota'}{$item} ne '') {                      if ($quotahash{'quotas'}{$key}{$item} ne '') {
                         if ($defquota eq '') {                          if ($defquota eq '') {
                             $defquota = $quotahash{'quotas'}{'defaultquota'}{$item};                              $defquota = $quotahash{'quotas'}{$key}{$item};
                             $settingstatus = $item;                              $settingstatus = $item;
                         } elsif ($quotahash{'quotas'}{'defaultquota'}{$item} > $defquota) {                          } elsif ($quotahash{'quotas'}{$key}{$item} > $defquota) {
                             $defquota = $quotahash{'quotas'}{'defaultquota'}{$item};                              $defquota = $quotahash{'quotas'}{$key}{$item};
                             $settingstatus = $item;                              $settingstatus = $item;
                         }                          }
                     }                      }
                 } else {                  } elsif ($key eq 'defaultquota') {
                     if ($quotahash{'quotas'}{$item} ne '') {                      if ($quotahash{'quotas'}{$item} ne '') {
                         if ($defquota eq '') {                          if ($defquota eq '') {
                             $defquota = $quotahash{'quotas'}{$item};                              $defquota = $quotahash{'quotas'}{$item};
Line 8136  sub default_quota { Line 8901  sub default_quota {
             }              }
         }          }
         if ($defquota eq '') {          if ($defquota eq '') {
             if (ref($quotahash{'quotas'}{'defaultquota'}) eq 'HASH') {              if (ref($quotahash{'quotas'}{$key}) eq 'HASH') {
                 $defquota = $quotahash{'quotas'}{'defaultquota'}{'default'};                  $defquota = $quotahash{'quotas'}{$key}{'default'};
             } else {              } elsif ($key eq 'defaultquota') {
                 $defquota = $quotahash{'quotas'}{'default'};                  $defquota = $quotahash{'quotas'}{'default'};
             }              }
             $settingstatus = 'default';              $settingstatus = 'default';
               if ($defquota eq '') {
                   if ($quotaname eq 'author') {
                       $defquota = 500;
                   }
               }
         }          }
     } else {      } else {
         $settingstatus = 'default';          $settingstatus = 'default';
         $defquota = 20;          if ($quotaname eq 'author') {
               $defquota = 500;
           } else {
               $defquota = 20;
           }
     }      }
     if (wantarray) {      if (wantarray) {
         return ($defquota,$settingstatus);          return ($defquota,$settingstatus);
Line 8154  sub default_quota { Line 8928  sub default_quota {
     }      }
 }  }
   
   ###############################################
   
   =pod
   
   =item * &excess_filesize_warning()
   
   Returns warning message if upload of file to authoring space, or copying
   of existing file within authoring space will cause quota for the authoring
   space to be exceeded.
   
   Same, if upload of a file directly to a course/community via Course Editor
   will cause quota for uploaded content for the course to be exceeded.
   
   Inputs: 7 
   1. username or coursenum
   2. domain
   3. context ('author' or 'course')
   4. filename of file for which action is being requested
   5. filesize (kB) of file
   6. action being taken: copy or upload.
   7. quotatype (in course context -- official, unofficial, community or textbook).
   
   Returns: 1 scalar: HTML to display containing warning if quota would be exceeded,
            otherwise return null.
   
   =back
   
   =cut
   
   sub excess_filesize_warning {
       my ($uname,$udom,$context,$filename,$filesize,$action,$quotatype) = @_;
       my $current_disk_usage = 0;
       my $disk_quota = &get_user_quota($uname,$udom,$context,$quotatype); #expressed in MB
       if ($context eq 'author') {
           my $authorspace = $Apache::lonnet::perlvar{'lonDocRoot'}."/priv/$udom/$uname";
           $current_disk_usage = &Apache::lonnet::diskusage($udom,$uname,$authorspace);
       } else {
           foreach my $subdir ('docs','supplemental') {
               $current_disk_usage += &Apache::lonnet::diskusage($udom,$uname,"userfiles/$subdir",1);
           }
       }
       $disk_quota = int($disk_quota * 1000);
       if (($current_disk_usage + $filesize) > $disk_quota) {
           return '<p class="LC_warning">'.
                   &mt("Unable to $action [_1]. (size = [_2] kilobytes). Disk quota will be exceeded.",
                       '<span class="LC_filename">'.$filename.'</span>',$filesize).'</p>'.
                  '<p>'.&mt('Disk quota is [_1] kilobytes. Your current disk usage is [_2] kilobytes.',
                               $disk_quota,$current_disk_usage).
                  '</p>';
       }
       return;
   }
   
   ###############################################
   
   
   
   
 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 8511  sub user_rule_formats { Line 9343  sub user_rule_formats {
     my ($rules,$ruleorder) = &Apache::lonnet::inst_userrules($domain,$check);      my ($rules,$ruleorder) = &Apache::lonnet::inst_userrules($domain,$check);
     if ((ref($rules) eq 'HASH') && (ref($ruleorder) eq 'ARRAY')) {      if ((ref($rules) eq 'HASH') && (ref($ruleorder) eq 'ARRAY')) {
         if (@{$ruleorder} > 0) {          if (@{$ruleorder} > 0) {
             $output = '<br />'.&mt("$text{$check} with the following format(s) may <span class=\"LC_cusr_emph\">only</span> be used for verified users at [_1]:",$domdesc).' <ul>';              $output = '<br />'.
                         &mt($text{$check}.' with the following format(s) may [_1]only[_2] be used for verified users at [_3]:',
                             '<span class="LC_cusr_emph">','</span>',$domdesc).
                         ' <ul>';
             foreach my $rule (@{$ruleorder}) {              foreach my $rule (@{$ruleorder}) {
                 if (ref($curr_rules) eq 'ARRAY') {                  if (ref($curr_rules) eq 'ARRAY') {
                     if (grep(/^\Q$rule\E$/,@{$curr_rules})) {                      if (grep(/^\Q$rule\E$/,@{$curr_rules})) {
Line 8980  sub get_env_multiple { Line 9815  sub get_env_multiple {
   
 sub ask_for_embedded_content {  sub ask_for_embedded_content {
     my ($actionurl,$state,$allfiles,$codebase,$args)=@_;      my ($actionurl,$state,$allfiles,$codebase,$args)=@_;
     my (%subdependencies,%dependencies,%mapping,%existing,%newfiles,%pathchanges);      my (%subdependencies,%dependencies,%mapping,%existing,%newfiles,%pathchanges,
     my $num = 0;          %currsubfile,%unused,$rem);
       my $counter = 0;
       my $numnew = 0;
     my $numremref = 0;      my $numremref = 0;
     my $numinvalid = 0;      my $numinvalid = 0;
     my $numpathchg = 0;      my $numpathchg = 0;
     my $numexisting = 0;      my $numexisting = 0;
     my ($output,$upload_output,$toplevel,$url,$udom,$uname,$getpropath);      my $numunused = 0;
     if (($actionurl eq '/adm/portfolio') || ($actionurl eq '/adm/coursegrp_portfolio')) {      my ($output,$upload_output,$toplevel,$url,$udom,$uname,$getpropath,$cdom,$cnum,
           $fileloc,$filename,$delete_output,$modify_output,$title,$symb,$path,$navmap);
       my $heading = &mt('Upload embedded files');
       my $buttontext = &mt('Upload');
   
       if ($env{'request.course.id'}) {
           if ($actionurl eq '/adm/dependencies') {
               $navmap = Apache::lonnavmaps::navmap->new();
           }
           $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
           $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
       }
       if (($actionurl eq '/adm/portfolio') || 
           ($actionurl eq '/adm/coursegrp_portfolio')) {
         my $current_path='/';          my $current_path='/';
         if ($env{'form.currentpath'}) {          if ($env{'form.currentpath'}) {
             $current_path = $env{'form.currentpath'};              $current_path = $env{'form.currentpath'};
         }          }
         if ($actionurl eq '/adm/coursegrp_portfolio') {          if ($actionurl eq '/adm/coursegrp_portfolio') {
             $udom = $env{'course.'.$env{'request.course.id'}.'.domain'};              $udom = $cdom;
             $uname = $env{'course.'.$env{'request.course.id'}.'.num'};              $uname = $cnum;
             $url = '/userfiles/groups/'.$env{'form.group'}.'/portfolio';              $url = '/userfiles/groups/'.$env{'form.group'}.'/portfolio';
         } else {          } else {
             $udom = $env{'user.domain'};              $udom = $env{'user.domain'};
Line 9014  sub ask_for_embedded_content { Line 9864  sub ask_for_embedded_content {
         }          }
     } elsif ($actionurl eq '/adm/coursedocs') {      } elsif ($actionurl eq '/adm/coursedocs') {
         if (ref($args) eq 'HASH') {          if (ref($args) eq 'HASH') {
            $url = $args->{'docs_url'};              $url = $args->{'docs_url'};
            $toplevel = $url;              $toplevel = $url;
               if ($args->{'context'} eq 'paste') {
                   ($cdom,$cnum) = ($url =~ m{^\Q/uploaded/\E($match_domain)/($match_courseid)/});
                   ($path) = 
                       ($toplevel =~ m{^(\Q/uploaded/$cdom/$cnum/\E(?:docs|supplemental)/(?:default|\d+)/\d+)/});
                   $fileloc = &Apache::lonnet::filelocation('',$toplevel);
                   $fileloc =~ s{^/}{};
               }
           }
       } elsif ($actionurl eq '/adm/dependencies')  {
           if ($env{'request.course.id'} ne '') {
               if (ref($args) eq 'HASH') {
                   $url = $args->{'docs_url'};
                   $title = $args->{'docs_title'};
                   $toplevel = $url; 
                   unless ($toplevel =~ m{^/}) {
                       $toplevel = "/$url";
                   }
                   ($rem) = ($toplevel =~ m{^(.+/)[^/]+$});
                   if ($toplevel =~ m{^(\Q/uploaded/$cdom/$cnum/portfolio/syllabus\E)}) {
                       $path = $1;
                   } else {
                       ($path) =
                           ($toplevel =~ m{^(\Q/uploaded/$cdom/$cnum/\E(?:docs|supplemental)/(?:default|\d+)/\d+)/});
                   }
                   $fileloc = &Apache::lonnet::filelocation('',$toplevel);
                   $fileloc =~ s{^/}{};
                   ($filename) = ($fileloc =~ m{.+/([^/]+)$});
                   $heading = &mt('Status of dependencies in [_1]',"$title ($filename)");
               }
         }          }
     }      } elsif ($actionurl eq "/public/$cdom/$cnum/syllabus") {
     my $now = time();          $udom = $cdom;
     foreach my $embed_file (keys(%{$allfiles})) {          $uname = $cnum;
         my $absolutepath;          $url = "/uploaded/$cdom/$cnum/portfolio/syllabus";
           $toplevel = $url;
           $path = $url;
           $fileloc = &Apache::lonnet::filelocation('',$toplevel).'/';
           $fileloc =~ s{^/}{};
       }
       foreach my $file (keys(%{$allfiles})) {
           my $embed_file;
           if (($path eq "/uploaded/$cdom/$cnum/portfolio/syllabus") && ($file =~ m{^\Q$path/\E(.+)$})) {
               $embed_file = $1;
           } else {
               $embed_file = $file;
           }
           my ($absolutepath,$cleaned_file);
         if ($embed_file =~ m{^\w+://}) {          if ($embed_file =~ m{^\w+://}) {
             $newfiles{$embed_file} = 1;              $cleaned_file = $embed_file;
             $mapping{$embed_file} = $embed_file;              $newfiles{$cleaned_file} = 1;
               $mapping{$cleaned_file} = $embed_file;
         } else {          } else {
               $cleaned_file = &clean_path($embed_file);
             if ($embed_file =~ m{^/}) {              if ($embed_file =~ m{^/}) {
                 $absolutepath = $embed_file;                  $absolutepath = $embed_file;
                 $embed_file =~ s{^(/+)}{};  
             }              }
             if ($embed_file =~ m{/}) {              if ($cleaned_file =~ m{/}) {
                 my ($path,$fname) = ($embed_file =~ m{^(.+)/([^/]*)$});                  my ($path,$fname) = ($cleaned_file =~ m{^(.+)/([^/]*)$});
                 $path = &check_for_traversal($path,$url,$toplevel);                  $path = &check_for_traversal($path,$url,$toplevel);
                 my $item = $fname;                  my $item = $fname;
                 if ($path ne '') {                  if ($path ne '') {
Line 9047  sub ask_for_embedded_content { Line 9940  sub ask_for_embedded_content {
             } else {              } else {
                 $dependencies{$embed_file} = 1;                  $dependencies{$embed_file} = 1;
                 if ($absolutepath) {                  if ($absolutepath) {
                     $mapping{$embed_file} = $absolutepath;                      $mapping{$cleaned_file} = $absolutepath;
                 } else {                  } else {
                     $mapping{$embed_file} = $embed_file;                      $mapping{$cleaned_file} = $embed_file;
                 }                  }
             }              }
         }          }
     }      }
       my $dirptr = 16384;
     foreach my $path (keys(%subdependencies)) {      foreach my $path (keys(%subdependencies)) {
         my %currsubfile;          $currsubfile{$path} = {};
         if (($actionurl eq '/adm/portfolio') || ($actionurl eq '/adm/coursegrp_portfolio')) {           if (($actionurl eq '/adm/portfolio') || 
               ($actionurl eq '/adm/coursegrp_portfolio')) {
             my ($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') {
                 foreach my $line (@{$sublistref}) {                  foreach my $line (@{$sublistref}) {
                     my ($file_name,$rest) = split(/\&/,$line,2);                      my ($file_name,$rest) = split(/\&/,$line,2);
                     $currsubfile{$file_name} = 1;                      $currsubfile{$path}{$file_name} = 1;
                 }                  }
             }              }
         } elsif (($actionurl eq '/adm/upload') || ($actionurl eq '/adm/testbank')) {          } elsif (($actionurl eq '/adm/upload') || ($actionurl eq '/adm/testbank')) {
             if (opendir(my $dir,$url.'/'.$path)) {              if (opendir(my $dir,$url.'/'.$path)) {
                 my @subdir_list = grep(!/^\./,readdir($dir));                  my @subdir_list = grep(!/^\./,readdir($dir));
                 map {$currsubfile{$_} = 1;} @subdir_list;                  map {$currsubfile{$path}{$_} = 1;} @subdir_list;
               }
           } elsif (($actionurl eq '/adm/dependencies') ||
                    (($actionurl eq '/adm/coursedocs') && (ref($args) eq 'HASH') &&
                     ($args->{'context'} eq 'paste')) ||
                    ($actionurl eq "/public/$cdom/$cnum/syllabus")) {
               if ($env{'request.course.id'} ne '') {
                   my $dir;
                   if ($actionurl eq "/public/$cdom/$cnum/syllabus") {
                       $dir = $fileloc;
                   } else {
                       ($dir) = ($fileloc =~ m{^(.+/)[^/]+$});
                   }
                   if ($dir ne '') {
                       my ($sublistref,$listerror) =
                           &Apache::lonnet::dirlist($dir.$path,$cdom,$cnum,$getpropath,undef,'/');
                       if (ref($sublistref) eq 'ARRAY') {
                           foreach my $line (@{$sublistref}) {
                               my ($file_name,$dom,undef,$testdir,undef,undef,undef,undef,$size,
                                   undef,$mtime)=split(/\&/,$line,12);
                               unless (($testdir&$dirptr) ||
                                       ($file_name =~ /^\.\.?$/)) {
                                   $currsubfile{$path}{$file_name} = [$size,$mtime];
                               }
                           }
                       }
                   }
             }              }
         }          }
         foreach my $file (keys(%{$subdependencies{$path}})) {          foreach my $file (keys(%{$subdependencies{$path}})) {
             if ($currsubfile{$file}) {              if (exists($currsubfile{$path}{$file})) {
                 my $item = $path.'/'.$file;                  my $item = $path.'/'.$file;
                 unless ($mapping{$item} eq $item) {                  unless ($mapping{$item} eq $item) {
                     $pathchanges{$item} = 1;                      $pathchanges{$item} = 1;
Line 9083  sub ask_for_embedded_content { Line 10004  sub ask_for_embedded_content {
                 $newfiles{$path.'/'.$file} = 1;                  $newfiles{$path.'/'.$file} = 1;
             }              }
         }          }
           if ($actionurl eq '/adm/dependencies') {
               foreach my $path (keys(%currsubfile)) {
                   if (ref($currsubfile{$path}) eq 'HASH') {
                       foreach my $file (keys(%{$currsubfile{$path}})) {
                            unless ($subdependencies{$path}{$file}) {
                                next if (($rem ne '') &&
                                         (($env{"httpref.$rem"."$path/$file"} ne '') ||
                                          (ref($navmap) &&
                                          (($navmap->getResourceByUrl($rem."$path/$file") ne '') ||
                                           (($file =~ /^(.*\.s?html?)\.bak$/i) &&
                                            ($navmap->getResourceByUrl($rem."$path/$1")))))));
                                $unused{$path.'/'.$file} = 1; 
                            }
                       }
                   }
               }
           }
     }      }
     my %currfile;      my %currfile;
     if (($actionurl eq '/adm/portfolio') || ($actionurl eq '/adm/coursegrp_portfolio')) {      if (($actionurl eq '/adm/portfolio') ||
           ($actionurl eq '/adm/coursegrp_portfolio')) {
         my ($dirlistref,$listerror) =          my ($dirlistref,$listerror) =
             &Apache::lonnet::dirlist($url,$udom,$uname,$getpropath);              &Apache::lonnet::dirlist($url,$udom,$uname,$getpropath);
         if (ref($dirlistref) eq 'ARRAY') {          if (ref($dirlistref) eq 'ARRAY') {
Line 9099  sub ask_for_embedded_content { Line 10038  sub ask_for_embedded_content {
             my @dir_list = grep(!/^\./,readdir($dir));              my @dir_list = grep(!/^\./,readdir($dir));
             map {$currfile{$_} = 1;} @dir_list;              map {$currfile{$_} = 1;} @dir_list;
         }          }
       } elsif (($actionurl eq '/adm/dependencies') ||
                (($actionurl eq '/adm/coursedocs') && (ref($args) eq 'HASH') &&
                 ($args->{'context'} eq 'paste')) ||
                ($actionurl eq "/public/$cdom/$cnum/syllabus")) {
           if ($env{'request.course.id'} ne '') {
               my ($dir) = ($fileloc =~ m{^(.+/)[^/]+$});
               if ($dir ne '') {
                   my ($dirlistref,$listerror) =
                       &Apache::lonnet::dirlist($dir,$cdom,$cnum,$getpropath,undef,'/');
                   if (ref($dirlistref) eq 'ARRAY') {
                       foreach my $line (@{$dirlistref}) {
                           my ($file_name,$dom,undef,$testdir,undef,undef,undef,undef,
                               $size,undef,$mtime)=split(/\&/,$line,12);
                           unless (($testdir&$dirptr) ||
                                   ($file_name =~ /^\.\.?$/)) {
                               $currfile{$file_name} = [$size,$mtime];
                           }
                       }
                   }
               }
           }
     }      }
     foreach my $file (keys(%dependencies)) {      foreach my $file (keys(%dependencies)) {
         if ($currfile{$file}) {          if (exists($currfile{$file})) {
             unless ($mapping{$file} eq $file) {              unless ($mapping{$file} eq $file) {
                 $pathchanges{$file} = 1;                  $pathchanges{$file} = 1;
             }              }
Line 9111  sub ask_for_embedded_content { Line 10071  sub ask_for_embedded_content {
             $newfiles{$file} = 1;              $newfiles{$file} = 1;
         }          }
     }      }
       foreach my $file (keys(%currfile)) {
           unless (($file eq $filename) ||
                   ($file eq $filename.'.bak') ||
                   ($dependencies{$file})) {
               if ($actionurl eq '/adm/dependencies') {
                   unless ($toplevel =~ m{^\Q/uploaded/$cdom/$cnum/portfolio/syllabus\E}) {
                       next if (($rem ne '') &&
                                (($env{"httpref.$rem".$file} ne '') ||
                                 (ref($navmap) &&
                                 (($navmap->getResourceByUrl($rem.$file) ne '') ||
                                  (($file =~ /^(.*\.s?html?)\.bak$/i) &&
                                   ($navmap->getResourceByUrl($rem.$1)))))));
                   }
               }
               $unused{$file} = 1;
           }
       }
       if (($actionurl eq '/adm/coursedocs') && (ref($args) eq 'HASH') &&
           ($args->{'context'} eq 'paste')) {
           $counter = scalar(keys(%existing));
           $numpathchg = scalar(keys(%pathchanges));
           return ($output,$counter,$numpathchg,\%existing);
       } elsif (($actionurl eq "/public/$cdom/$cnum/syllabus") && 
                (ref($args) eq 'HASH') && ($args->{'context'} eq 'rewrites')) {
           $counter = scalar(keys(%existing));
           $numpathchg = scalar(keys(%pathchanges));
           return ($output,$counter,$numpathchg,\%existing,\%mapping);
       }
     foreach my $embed_file (sort {lc($a) cmp lc($b)} keys(%newfiles)) {      foreach my $embed_file (sort {lc($a) cmp lc($b)} keys(%newfiles)) {
           if ($actionurl eq '/adm/dependencies') {
               next if ($embed_file =~ m{^\w+://});
           }
         $upload_output .= &start_data_table_row().          $upload_output .= &start_data_table_row().
                           '<td><span class="LC_filename">'.$embed_file.'</span>';                            '<td valign="top"><img src="'.&icon($embed_file).'" />&nbsp;'.
                             '<span class="LC_filename">'.$embed_file.'</span>';
         unless ($mapping{$embed_file} eq $embed_file) {          unless ($mapping{$embed_file} eq $embed_file) {
             $upload_output .= '<br /><span class="LC_info" style="font-size:smaller;">'.&mt('changed from: [_1]',$mapping{$embed_file}).'</span>';              $upload_output .= '<br /><span class="LC_info" style="font-size:smaller;">'.
                                 &mt('changed from: [_1]',$mapping{$embed_file}).'</span>';
         }          }
         $upload_output .= '</td><td>';          $upload_output .= '</td>';
         if ($args->{'ignore_remote_references'}          if ($args->{'ignore_remote_references'} && $embed_file =~ m{^\w+://}) { 
             && $embed_file =~ m{^\w+://}) {              $upload_output.='<td align="right">'.
             $upload_output.='<span class="LC_warning">'.&mt("URL points to other server.").'</span>';                              '<span class="LC_info LC_fontsize_medium">'.
                               &mt("URL points to web address").'</span>';
             $numremref++;              $numremref++;
         } elsif ($args->{'error_on_invalid_names'}          } elsif ($args->{'error_on_invalid_names'}
             && $embed_file ne &Apache::lonnet::clean_filename($embed_file,{'keep_path' => 1,})) {              && $embed_file ne &Apache::lonnet::clean_filename($embed_file,{'keep_path' => 1,})) {
               $upload_output.='<td align="right"><span class="LC_warning">'.
             $upload_output.='<span class="LC_warning">'.&mt('Invalid characters').'</span>';                              &mt('Invalid characters').'</span>';
             $numinvalid++;              $numinvalid++;
         } else {          } else {
             $upload_output .= &embedded_file_element('upload_embedded',$num,              $upload_output .= '<td>'.
                                 &embedded_file_element('upload_embedded',$counter,
                                                      $embed_file,\%mapping,                                                       $embed_file,\%mapping,
                                                      $allfiles,$codebase);                                                       $allfiles,$codebase,'upload');
             $num++;              $counter ++;
               $numnew ++;
         }          }
         $upload_output .= '</td>'.&Apache::loncommon::end_data_table_row()."\n";          $upload_output .= '</td>'.&Apache::loncommon::end_data_table_row()."\n";
     }      }
     foreach my $embed_file (sort {lc($a) cmp lc($b)} keys(%existing)) {      foreach my $embed_file (sort {lc($a) cmp lc($b)} keys(%existing)) {
         $upload_output .= &start_data_table_row().          if ($actionurl eq '/adm/dependencies') {
                           '<td><span class="LC_filename">'.$embed_file.'</span></td>'.              my ($size,$mtime) = &get_dependency_details(\%currfile,\%currsubfile,$embed_file);
                           '<td><span class="LC_warning">'.&mt('Already exists').'</span></td>'.              $modify_output .= &start_data_table_row().
                           &Apache::loncommon::end_data_table_row()."\n";                                '<td><a href="'.$path.'/'.$embed_file.'" style="text-decoration:none;">'.
                                 '<img src="'.&icon($embed_file).'" border="0" />'.
                                 '&nbsp;<span class="LC_filename">'.$embed_file.'</span></a></td>'.
                                 '<td>'.$size.'</td>'.
                                 '<td>'.$mtime.'</td>'.
                                 '<td><label><input type="checkbox" name="mod_upload_dep" '.
                                 'onclick="toggleBrowse('."'$counter'".')" id="mod_upload_dep_'.
                                 $counter.'" value="'.$counter.'" />'.&mt('Yes').'</label>'.
                                 '<div id="moduploaddep_'.$counter.'" style="display:none;">'.
                                 &embedded_file_element('upload_embedded',$counter,
                                                        $embed_file,\%mapping,
                                                        $allfiles,$codebase,'modify').
                                 '</div></td>'.
                                 &end_data_table_row()."\n";
               $counter ++;
           } else {
               $upload_output .= &start_data_table_row().
                                 '<td valign="top"><img src="'.&icon($embed_file).'" />&nbsp;'.
                                 '<span class="LC_filename">'.$embed_file.'</span></td>'.
                                 '<td align="right"><span class="LC_info LC_fontsize_medium">'.&mt('Already exists').'</span></td>'.
                                 &Apache::loncommon::end_data_table_row()."\n";
           }
       }
       my $delidx = $counter;
       foreach my $oldfile (sort {lc($a) cmp lc($b)} keys(%unused)) {
           my ($size,$mtime) = &get_dependency_details(\%currfile,\%currsubfile,$oldfile);
           $delete_output .= &start_data_table_row().
                             '<td><img src="'.&icon($oldfile).'" />'.
                             '&nbsp;<span class="LC_filename">'.$oldfile.'</span></td>'.
                             '<td>'.$size.'</td>'.
                             '<td>'.$mtime.'</td>'.
                             '<td><label><input type="checkbox" name="del_upload_dep" '.
                             ' value="'.$delidx.'" />'.&mt('Yes').'</label>'.
                             &embedded_file_element('upload_embedded',$delidx,
                                                    $oldfile,\%mapping,$allfiles,
                                                    $codebase,'delete').'</td>'.
                             &end_data_table_row()."\n"; 
           $numunused ++;
           $delidx ++;
     }      }
     if ($upload_output) {      if ($upload_output) {
         $upload_output = &start_data_table().          $upload_output = &start_data_table().
                          $upload_output.                           $upload_output.
                          &end_data_table()."\n";                           &end_data_table()."\n";
     }      }
       if ($modify_output) {
           $modify_output = &start_data_table().
                            &start_data_table_header_row().
                            '<th>'.&mt('File').'</th>'.
                            '<th>'.&mt('Size (KB)').'</th>'.
                            '<th>'.&mt('Modified').'</th>'.
                            '<th>'.&mt('Upload replacement?').'</th>'.
                            &end_data_table_header_row().
                            $modify_output.
                            &end_data_table()."\n";
       }
       if ($delete_output) {
           $delete_output = &start_data_table().
                            &start_data_table_header_row().
                            '<th>'.&mt('File').'</th>'.
                            '<th>'.&mt('Size (KB)').'</th>'.
                            '<th>'.&mt('Modified').'</th>'.
                            '<th>'.&mt('Delete?').'</th>'.
                            &end_data_table_header_row().
                            $delete_output.
                            &end_data_table()."\n";
       }
     my $applies = 0;      my $applies = 0;
     if ($numremref) {      if ($numremref) {
         $applies ++;          $applies ++;
Line 9156  sub ask_for_embedded_content { Line 10212  sub ask_for_embedded_content {
     if ($numexisting) {      if ($numexisting) {
         $applies ++;          $applies ++;
     }      }
     if ($num) {      if ($counter || $numunused) {
         $output = '<form name="upload_embedded" action="'.$actionurl.'"'.          $output = '<form name="upload_embedded" action="'.$actionurl.'"'.
                   ' method="post" enctype="multipart/form-data">'."\n".                    ' method="post" enctype="multipart/form-data">'."\n".
                   $state.                    $state.'<h3>'.$heading.'</h3>'; 
                   '<h3>'.&mt('Upload embedded files').          if ($actionurl eq '/adm/dependencies') {
                   ':</h3>'.$upload_output.'<br />'."\n".              if ($numnew) {
                   '<input type ="hidden" name="number_embedded_items" value="'.                  $output .= '<h4>'.&mt('Missing dependencies').'</h4>'.
                   $num.'" />'."\n";                             '<p>'.&mt('The following files need to be uploaded.').'</p>'."\n".
         if ($actionurl eq '') {                             $upload_output.'<br />'."\n";
               }
               if ($numexisting) {
                   $output .= '<h4>'.&mt('Uploaded dependencies (in use)').'</h4>'.
                              '<p>'.&mt('Upload a new file to replace the one currently in use.').'</p>'."\n".
                              $modify_output.'<br />'."\n";
                              $buttontext = &mt('Save changes');
               }
               if ($numunused) {
                   $output .= '<h4>'.&mt('Unused files').'</h4>'.
                              '<p>'.&mt('The following uploaded files are no longer used.').'</p>'."\n".
                              $delete_output.'<br />'."\n";
                              $buttontext = &mt('Save changes');
               }
           } else {
               $output .= $upload_output.'<br />'."\n";
           }
           $output .= '<input type ="hidden" name="number_embedded_items" value="'.
                      $counter.'" />'."\n";
           if ($actionurl eq '/adm/dependencies') { 
               $output .= '<input type ="hidden" name="number_newemb_items" value="'.
                          $numnew.'" />'."\n";
           } elsif ($actionurl eq '') {
             $output .=  '<input type="hidden" name="phase" value="three" />';              $output .=  '<input type="hidden" name="phase" value="three" />';
         }          }
     } elsif ($applies) {      } elsif ($applies) {
         $output = '<b>'.&mt('Referenced files').'</b>:<br />';          $output = '<b>'.&mt('Referenced files').'</b>:<br />';
         if ($applies > 1) {          if ($applies > 1) {
             $output .=                $output .=  
                 &mt('No files need to be uploaded, as one of the following applies to each reference:').'<ul>';                  &mt('No dependencies need to be uploaded, as one of the following applies to each reference:').'<ul>';
             if ($numremref) {              if ($numremref) {
                 $output .= '<li>'.&mt('reference is to a URL which points to another server').'</li>'."\n";                  $output .= '<li>'.&mt('reference is to a URL which points to another server').'</li>'."\n";
             }              }
Line 9192  sub ask_for_embedded_content { Line 10270  sub ask_for_embedded_content {
         $output .= $upload_output.'<br />';          $output .= $upload_output.'<br />';
     }      }
     my ($pathchange_output,$chgcount);      my ($pathchange_output,$chgcount);
     $chgcount = $num;      $chgcount = $counter;
     if (keys(%pathchanges) > 0) {      if (keys(%pathchanges) > 0) {
         foreach my $embed_file (sort {lc($a) cmp lc($b)} keys(%pathchanges)) {          foreach my $embed_file (sort {lc($a) cmp lc($b)} keys(%pathchanges)) {
             if ($num) {              if ($counter) {
                 $output .= &embedded_file_element('pathchange',$chgcount,                  $output .= &embedded_file_element('pathchange',$chgcount,
                                                   $embed_file,\%mapping,                                                    $embed_file,\%mapping,
                                                   $allfiles,$codebase);                                                    $allfiles,$codebase,'change');
             } else {              } else {
                 $pathchange_output .=                   $pathchange_output .= 
                     &start_data_table_row().                      &start_data_table_row().
Line 9207  sub ask_for_embedded_content { Line 10285  sub ask_for_embedded_content {
                     '<td>'.$mapping{$embed_file}.'</td>'.                      '<td>'.$mapping{$embed_file}.'</td>'.
                     '<td>'.$embed_file.                      '<td>'.$embed_file.
                     &embedded_file_element('pathchange',$numpathchg,$embed_file,                      &embedded_file_element('pathchange',$numpathchg,$embed_file,
                                            \%mapping,$allfiles,$codebase).                                             \%mapping,$allfiles,$codebase,'change').
                     '</td>'.&end_data_table_row();                      '</td>'.&end_data_table_row();
             }              }
             $numpathchg ++;              $numpathchg ++;
             $chgcount ++;              $chgcount ++;
         }          }
     }      }
     if ($num) {      if (($counter) || ($numunused)) {
         if ($numpathchg) {          if ($numpathchg) {
             $output .= '<input type ="hidden" name="number_pathchange_items" value="'.              $output .= '<input type ="hidden" name="number_pathchange_items" value="'.
                        $numpathchg.'" />'."\n";                         $numpathchg.'" />'."\n";
Line 9224  sub ask_for_embedded_content { Line 10302  sub ask_for_embedded_content {
             $output .= '<input type="hidden" name="phase" value="three" />'."\n";              $output .= '<input type="hidden" name="phase" value="three" />'."\n";
         } elsif ($actionurl eq '/adm/portfolio' || $actionurl eq '/adm/coursegrp_portfolio') {          } elsif ($actionurl eq '/adm/portfolio' || $actionurl eq '/adm/coursegrp_portfolio') {
             $output .= '<input type="hidden" name="action" value="upload_embedded" />';              $output .= '<input type="hidden" name="action" value="upload_embedded" />';
           } elsif ($actionurl eq '/adm/dependencies') {
               $output .= '<input type="hidden" name="action" value="process_changes" />';
         }          }
         $output .=  '<input type ="submit" value="'.&mt('Upload Listed Files').'" />'."\n".          $output .= '<input type ="submit" value="'.$buttontext.'" />'."\n".'</form>'."\n";
                     &mt('(only files for which a location has been provided will be uploaded)').'</form>'."\n";  
     } elsif ($numpathchg) {      } elsif ($numpathchg) {
         my %pathchange = ();          my %pathchange = ();
         $output .= &modify_html_form('pathchange',$actionurl,$state,\%pathchange,$pathchange_output);          $output .= &modify_html_form('pathchange',$actionurl,$state,\%pathchange,$pathchange_output);
         if (($actionurl eq '/adm/portfolio') || ($actionurl eq '/adm/coursegrp_portfolio')) {          if (($actionurl eq '/adm/portfolio') || ($actionurl eq '/adm/coursegrp_portfolio')) {
             $output .= '<p>'.&mt('or').'</p>';               $output .= '<p>'.&mt('or').'</p>'; 
         }           }
       }
       return ($output,$counter,$numpathchg);
   }
   
   =pod
   
   =item * clean_path($name)
   
   Performs clean-up of directories, subdirectories and filename in an
   embedded object, referenced in an HTML file which is being uploaded
   to a course or portfolio, where 
   "Upload embedded images/multimedia files if HTML file" checkbox was
   checked.
   
   Clean-up is similar to replacements in lonnet::clean_filename()
   except each / between sub-directory and next level is preserved.
   
   =cut
   
   sub clean_path {
       my ($embed_file) = @_;
       $embed_file =~s{^/+}{};
       my @contents;
       if ($embed_file =~ m{/}) {
           @contents = split(/\//,$embed_file);
       } else {
           @contents = ($embed_file);
       }
       my $lastidx = scalar(@contents)-1;
       for (my $i=0; $i<=$lastidx; $i++) { 
           $contents[$i]=~s{\\}{/}g;
           $contents[$i]=~s/\s+/\_/g;
           $contents[$i]=~s{[^/\w\.\-]}{}g;
           if ($i == $lastidx) {
               $contents[$i]=~s/\.(\d+)(?=\.)/_$1/g;
           }
       }
       if ($lastidx > 0) {
           return join('/',@contents);
       } else {
           return $contents[0];
     }      }
     return ($output,$num,$numpathchg);  
 }  }
   
 sub embedded_file_element {  sub embedded_file_element {
     my ($context,$num,$embed_file,$mapping,$allfiles,$codebase) = @_;      my ($context,$num,$embed_file,$mapping,$allfiles,$codebase,$type) = @_;
     return unless ((ref($mapping) eq 'HASH') && (ref($allfiles) eq 'HASH') &&      return unless ((ref($mapping) eq 'HASH') && (ref($allfiles) eq 'HASH') &&
                    (ref($codebase) eq 'HASH'));                     (ref($codebase) eq 'HASH'));
     my $output;      my $output;
     if ($context eq 'upload_embedded') {      if (($context eq 'upload_embedded') && ($type ne 'delete')) {
        $output = '<input name="embedded_item_'.$num.'" type="file" value="" />'."\n";         $output = '<input name="embedded_item_'.$num.'" type="file" value="" />'."\n";
     }      }
     $output .= '<input name="embedded_orig_'.$num.'" type="hidden" value="'.      $output .= '<input name="embedded_orig_'.$num.'" type="hidden" value="'.
Line 9269  sub embedded_file_element { Line 10388  sub embedded_file_element {
     return $output;      return $output;
 }  }
   
   sub get_dependency_details {
       my ($currfile,$currsubfile,$embed_file) = @_;
       my ($size,$mtime,$showsize,$showmtime);
       if ((ref($currfile) eq 'HASH') && (ref($currsubfile))) {
           if ($embed_file =~ m{/}) {
               my ($path,$fname) = split(/\//,$embed_file);
               if (ref($currsubfile->{$path}{$fname}) eq 'ARRAY') {
                   ($size,$mtime) = @{$currsubfile->{$path}{$fname}};
               }
           } else {
               if (ref($currfile->{$embed_file}) eq 'ARRAY') {
                   ($size,$mtime) = @{$currfile->{$embed_file}};
               }
           }
           $showsize = $size/1024.0;
           $showsize = sprintf("%.1f",$showsize);
           if ($mtime > 0) {
               $showmtime = &Apache::lonlocal::locallocaltime($mtime);
           }
       }
       return ($showsize,$showmtime);
   }
   
   sub ask_embedded_js {
       return <<"END";
   <script type="text/javascript"">
   // <![CDATA[
   function toggleBrowse(counter) {
       var chkboxid = document.getElementById('mod_upload_dep_'+counter);
       var fileid = document.getElementById('embedded_item_'+counter);
       var uploaddivid = document.getElementById('moduploaddep_'+counter);
       if (chkboxid.checked == true) {
           uploaddivid.style.display='block';
       } else {
           uploaddivid.style.display='none';
           fileid.value = '';
       }
   }
   // ]]>
   </script>
   
   END
   }
   
 sub upload_embedded {  sub upload_embedded {
     my ($context,$dirpath,$uname,$udom,$dir_root,$url_root,$group,$disk_quota,      my ($context,$dirpath,$uname,$udom,$dir_root,$url_root,$group,$disk_quota,
         $current_disk_usage,$hiddenstate,$actionurl) = @_;          $current_disk_usage,$hiddenstate,$actionurl) = @_;
Line 9317  sub upload_embedded { Line 10480  sub upload_embedded {
         # Check if extension is valid          # Check if extension is valid
         if (($fname =~ /\.(\w+)$/) &&          if (($fname =~ /\.(\w+)$/) &&
             (&Apache::loncommon::fileembstyle($1) eq 'hdn')) {              (&Apache::loncommon::fileembstyle($1) eq 'hdn')) {
             $output .= &mt('Invalid file extension ([_1]) - reserved for LONCAPA use - rename the file with a different extension and re-upload. ',$1).'<br />';              $output .= &mt('Invalid file extension ([_1]) - reserved for internal use.',$1)
                         .' '.&mt('Rename the file with a different extension and re-upload.').'<br />';
             next;              next;
         } elsif (($fname =~ /\.(\w+)$/) &&          } elsif (($fname =~ /\.(\w+)$/) &&
                  (!defined(&Apache::loncommon::fileembstyle($1)))) {                   (!defined(&Apache::loncommon::fileembstyle($1)))) {
             $output .= &mt('Unrecognized file extension ([_1]) - rename the file with a proper extension and re-upload.',$1).'<br />';              $output .= &mt('Unrecognized file extension ([_1]) - rename the file with a proper extension and re-upload.',$1).'<br />';
             next;              next;
         } elsif ($fname=~/\.(\d+)\.(\w+)$/) {          } elsif ($fname=~/\.(\d+)\.(\w+)$/) {
             $output .= &mt('File name not allowed - rename the file to remove the number immediately before the file extension([_1]) and re-upload.',$2).'<br />';              $output .= &mt('Filename not allowed - rename the file to remove the number immediately before the file extension([_1]) and re-upload.',$2).'<br />';
             next;              next;
         }          }
   
         $env{'form.embedded_item_'.$i.'.filename'}=$fname;          $env{'form.embedded_item_'.$i.'.filename'}=$fname;
           my $subdir = $path;
           $subdir =~ s{/+$}{};
         if ($context eq 'portfolio') {          if ($context eq 'portfolio') {
             my $result;              my $result;
             if ($state eq 'existingfile') {              if ($state eq 'existingfile') {
                 $result=                  $result=
                     &Apache::lonnet::userfileupload('embedded_item_'.$i,'existingfile',                      &Apache::lonnet::userfileupload('embedded_item_'.$i,'existingfile',
                                                     $dirpath.$env{'form.currentpath'}.$path);                                                      $dirpath.$env{'form.currentpath'}.$subdir);
             } else {              } else {
                 $result=                  $result=
                     &Apache::lonnet::userfileupload('embedded_item_'.$i,'',                      &Apache::lonnet::userfileupload('embedded_item_'.$i,'',
                                                     $dirpath.                                                      $dirpath.
                                                     $env{'form.currentpath'}.$path);                                                      $env{'form.currentpath'}.$subdir);
                 if ($result !~ m|^/uploaded/|) {                  if ($result !~ m|^/uploaded/|) {
                     $output .= '<span class="LC_error">'                      $output .= '<span class="LC_error">'
                                .&mt('An error occurred ([_1]) while trying to upload [_2] for embedded element [_3].'                                 .&mt('An error occurred ([_1]) while trying to upload [_2] for embedded element [_3].'
Line 9351  sub upload_embedded { Line 10516  sub upload_embedded {
                                $path.$fname.'</span>').'<br />';                                      $path.$fname.'</span>').'<br />';     
                 }                  }
             }              }
         } elsif ($context eq 'coursedoc') {          } elsif (($context eq 'coursedoc') || ($context eq 'syllabus')) {
               my $extendedsubdir = $dirpath.'/'.$subdir;
               $extendedsubdir =~ s{/+$}{};
             my $result =              my $result =
                 &Apache::lonnet::userfileupload('embedded_item_'.$i,'coursedoc',                  &Apache::lonnet::userfileupload('embedded_item_'.$i,$context,$extendedsubdir);
                                                 $dirpath.'/'.$path);  
             if ($result !~ m|^/uploaded/|) {              if ($result !~ m|^/uploaded/|) {
                 $output .= '<span class="LC_error">'                  $output .= '<span class="LC_error">'
                            .&mt('An error occurred ([_1]) while trying to upload [_2] for embedded element [_3].'                             .&mt('An error occurred ([_1]) while trying to upload [_2] for embedded element [_3].'
Line 9364  sub upload_embedded { Line 10530  sub upload_embedded {
             } else {              } else {
                 $output .= &mt('Uploaded [_1]','<span class="LC_filename">'.                  $output .= &mt('Uploaded [_1]','<span class="LC_filename">'.
                            $path.$fname.'</span>').'<br />';                             $path.$fname.'</span>').'<br />';
                   if ($context eq 'syllabus') {
                       &Apache::lonnet::make_public_indefinitely($result);
                   }
             }              }
         } else {          } else {
 # Save the file  # Save the file
Line 9384  sub upload_embedded { Line 10553  sub upload_embedded {
             if (!open($fh,'>'.$dest)) {              if (!open($fh,'>'.$dest)) {
                 &Apache::lonnet::logthis('Failed to create '.$dest);                  &Apache::lonnet::logthis('Failed to create '.$dest);
                 $output .= '<span class="LC_error">'.                  $output .= '<span class="LC_error">'.
                            &mt('An error occurred while trying to upload [_1] for embedded element [_2].',$orig_uploaded_filename,$env{'form.embedded_orig_'.$i}).                             &mt('An error occurred while trying to upload [_1] for embedded element [_2].',
                                  $orig_uploaded_filename,$env{'form.embedded_orig_'.$i}).
                            '</span><br />';                             '</span><br />';
             } else {              } else {
                 if (!print $fh $env{'form.embedded_item_'.$i}) {                  if (!print $fh $env{'form.embedded_item_'.$i}) {
                     &Apache::lonnet::logthis('Failed to write to '.$dest);                      &Apache::lonnet::logthis('Failed to write to '.$dest);
                     $output .= '<span class="LC_error">'.                      $output .= '<span class="LC_error">'.
                               &mt('An error occurred while writing the file [_1] for embedded element [_2].',$orig_uploaded_filename,$env{'form.embedded_orig_'.$i}).                                &mt('An error occurred while writing the file [_1] for embedded element [_2].',
                                     $orig_uploaded_filename,$env{'form.embedded_orig_'.$i}).
                               '</span><br />';                                '</span><br />';
                 } else {                  } else {
                     $output .= &mt('Uploaded [_1]','<span class="LC_filename">'.                      $output .= &mt('Uploaded [_1]','<span class="LC_filename">'.
Line 9412  sub upload_embedded { Line 10583  sub upload_embedded {
     }      }
     $output .= &modify_html_form('upload_embedded',$actionurl,$hiddenstate,\%pathchange);      $output .= &modify_html_form('upload_embedded',$actionurl,$hiddenstate,\%pathchange);
     $returnflag = 'ok';      $returnflag = 'ok';
     if (keys(%pathchange) > 0) {      my $numpathchgs = scalar(keys(%pathchange));
       if ($numpathchgs > 0) {
         if ($context eq 'portfolio') {          if ($context eq 'portfolio') {
             $output .= '<p>'.&mt('or').'</p>';              $output .= '<p>'.&mt('or').'</p>';
         } elsif ($context eq 'testbank') {          } elsif ($context eq 'testbank') {
             $output .=  '<p>'.&mt('Or [_1]continue[_2] the testbank import without modifying the reference(s).','<a href="javascript:document.testbankForm.submit();">','</a>').'</p>';              $output .=  '<p>'.&mt('Or [_1]continue[_2] the testbank import without modifying the reference(s).',
                                     '<a href="javascript:document.testbankForm.submit();">','</a>').'</p>';
             $returnflag = 'modify_orightml';              $returnflag = 'modify_orightml';
         }          }
     }      }
     return ($output.$footer,$returnflag);      return ($output.$footer,$returnflag,$numpathchgs);
 }  }
   
 sub modify_html_form {  sub modify_html_form {
Line 9455  sub modify_html_form { Line 10628  sub modify_html_form {
                     '<input type="hidden" name="embedded_orig_'.$i.'" value="'.                      '<input type="hidden" name="embedded_orig_'.$i.'" value="'.
                     &escape($env{'form.embedded_orig_'.$i}).'" /></td>'.                      &escape($env{'form.embedded_orig_'.$i}).'" /></td>'.
                     &end_data_table_row();                      &end_data_table_row();
             }               }
         }          }
     } else {      } else {
         $modifyform = $pathchgtable;          $modifyform = $pathchgtable;
Line 9466  sub modify_html_form { Line 10639  sub modify_html_form {
         }          }
     }      }
     if ($modifyform) {      if ($modifyform) {
           if ($actionurl eq '/adm/dependencies') {
               $hiddenstate .= '<input type="hidden" name="action" value="modifyhrefs" />';
           }
         return '<h3>'.&mt('Changes in content of HTML file required').'</h3>'."\n".          return '<h3>'.&mt('Changes in content of HTML file required').'</h3>'."\n".
                '<p>'.&mt('Changes need to be made to the reference(s) used for one or more of the dependencies, if your HTML file is to work correctly:').'<ol>'."\n".                 '<p>'.&mt('Changes need to be made to the reference(s) used for one or more of the dependencies, if your HTML file is to work correctly:').'<ol>'."\n".
                '<li>'.&mt('For consistency between the reference(s) and the location of the corresponding stored file within LON-CAPA.').'</li>'."\n".                 '<li>'.&mt('For consistency between the reference(s) and the location of the corresponding stored file within LON-CAPA.').'</li>'."\n".
Line 9488  sub modify_html_form { Line 10664  sub modify_html_form {
 }  }
   
 sub modify_html_refs {  sub modify_html_refs {
     my ($context,$dirpath,$uname,$udom,$dir_root) = @_;      my ($context,$dirpath,$uname,$udom,$dir_root,$url) = @_;
     my $container;      my $container;
     if ($context eq 'portfolio') {      if ($context eq 'portfolio') {
         $container = $env{'form.container'};          $container = $env{'form.container'};
     } elsif ($context eq 'coursedoc') {      } elsif ($context eq 'coursedoc') {
         $container = $env{'form.primaryurl'};          $container = $env{'form.primaryurl'};
       } elsif ($context eq 'manage_dependencies') {
           (undef,undef,$container) = &Apache::lonnet::decode_symb($env{'form.symb'});
           $container = "/$container";
       } elsif ($context eq 'syllabus') {
           $container = $url;
     } else {      } else {
         $container = $Apache::lonnet::perlvar{'lonDocRoot'}.$env{'form.filename'};          $container = $Apache::lonnet::perlvar{'lonDocRoot'}.$env{'form.filename'};
     }      }
     my (%allfiles,%codebase,$output,$content);      my (%allfiles,%codebase,$output,$content);
     my @changes = &get_env_multiple('form.namechange');      my @changes = &get_env_multiple('form.namechange');
     return unless (@changes > 0);      unless ((@changes > 0) || ($context eq 'syllabus')) {
     if (($context eq 'portfolio') || ($context eq 'coursedoc')) {          if (wantarray) {
         return unless ($container =~ m{^/uploaded/\Q$udom\E/\Q$uname\E/});              return ('',0,0); 
           } else {
               return;
           }
       }
       if (($context eq 'portfolio') || ($context eq 'coursedoc') || 
           ($context eq 'manage_dependencies') || ($context eq 'syllabus')) {
           unless ($container =~ m{^/uploaded/\Q$udom\E/\Q$uname\E/}) {
               if (wantarray) {
                   return ('',0,0);
               } else {
                   return;
               }
           } 
         $content = &Apache::lonnet::getfile($container);          $content = &Apache::lonnet::getfile($container);
         return if ($content eq '-1');          if ($content eq '-1') {
               if (wantarray) {
                   return ('',0,0);
               } else {
                   return;
               }
           }
     } else {      } else {
         return unless ($container =~ /^\Q$dir_root\E/);           unless ($container =~ /^\Q$dir_root\E/) {
               if (wantarray) {
                   return ('',0,0);
               } else {
                   return;
               }
           } 
         if (open(my $fh,"<$container")) {          if (open(my $fh,"<$container")) {
             $content = join('', <$fh>);              $content = join('', <$fh>);
             close($fh);              close($fh);
         } else {          } else {
             return;              if (wantarray) {
                   return ('',0,0);
               } else {
                   return;
               }
         }          }
     }      }
     my ($count,$codebasecount) = (0,0);      my ($count,$codebasecount) = (0,0);
Line 9534  sub modify_html_refs { Line 10744  sub modify_html_refs {
                     if ($content =~ m{($attrib_regexp\s*=\s*['"]?)\Q$ref\E(['"]?)}) {                      if ($content =~ m{($attrib_regexp\s*=\s*['"]?)\Q$ref\E(['"]?)}) {
                         my $numchg = ($content =~ s{($attrib_regexp\s*=\s*['"]?)\Q$ref\E(['"]?)}{$1$newname$2}gi);                          my $numchg = ($content =~ s{($attrib_regexp\s*=\s*['"]?)\Q$ref\E(['"]?)}{$1$newname$2}gi);
                         $count += $numchg;                          $count += $numchg;
                           $allfiles{$newname} = $allfiles{$ref};
                           delete($allfiles{$ref});
                     }                      }
                     if ($env{'form.embedded_codebase_'.$i} ne '') {                      if ($env{'form.embedded_codebase_'.$i} ne '') {
                         $codebase = &unescape($env{'form.embedded_codebase_'.$i});                          $codebase = &unescape($env{'form.embedded_codebase_'.$i});
Line 9542  sub modify_html_refs { Line 10754  sub modify_html_refs {
                     }                      }
                 }                  }
             }              }
               my $skiprewrites;
             if ($count || $codebasecount) {              if ($count || $codebasecount) {
                 my $saveresult;                  my $saveresult;
                 if ($context eq 'portfolio' || $context eq 'coursedoc') {                  if (($context eq 'portfolio') || ($context eq 'coursedoc') || 
                       ($context eq 'manage_dependencies') || ($context eq 'syllabus')) {
                     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{/([^/]+)$});
                         $output = '<p>'.&mt('Updated [quant,_1,reference] in [_2].',                          $output = '<p>'.&mt('Updated [quant,_1,reference] in [_2].',
                                             $count,'<span class="LC_filename">'.                                              $count,'<span class="LC_filename">'.
                                             $fname.'</span>').'</p>';                                               $fname.'</span>').'</p>';
                     } else {                      } else {
                          $output = '<p class="LC_error">'.                           $output = '<p class="LC_error">'.
                                    &mt('Error: update failed for: [_1].',                                     &mt('Error: update failed for: [_1].',
                                    '<span class="LC_filename">'.                                     '<span class="LC_filename">'.
                                    $container.'</span>').'</p>';                                     $container.'</span>').'</p>';
                     }                      }
                       if ($context eq 'syllabus') {
                           unless ($saveresult eq 'ok') {
                               $skiprewrites = 1;
                           }
                       }
                 } else {                  } else {
                     if (open(my $fh,">$container")) {                      if (open(my $fh,">$container")) {
                         print $fh $content;                          print $fh $content;
Line 9572  sub modify_html_refs { Line 10791  sub modify_html_refs {
                     }                      }
                 }                  }
             }              }
               if (($context eq 'syllabus') && (!$skiprewrites)) {
                   my ($actionurl,$state);
                   $actionurl = "/public/$udom/$uname/syllabus";
                   my ($ignore,$num,$numpathchanges,$existing,$mapping) =
                       &ask_for_embedded_content($actionurl,$state,\%allfiles,
                                                 \%codebase,
                                                 {'context' => 'rewrites',
                                                  'ignore_remote_references' => 1,});
                   if (ref($mapping) eq 'HASH') {
                       my $rewrites = 0;
                       foreach my $key (keys(%{$mapping})) {
                           next if ($key =~ m{^https?://});
                           my $ref = $mapping->{$key};
                           my $newname = "/uploaded/$udom/$uname/portfolio/syllabus/$key";
                           my $attrib;
                           if (ref($allfiles{$mapping->{$key}}) eq 'ARRAY') {
                               $attrib = join('|',@{$allfiles{$mapping->{$key}}});
                           }
                           if ($content =~ m{($attrib\s*=\s*['"]?)\Q$ref\E(['"]?)}) {
                               my $numchg = ($content =~ s{($attrib\s*=\s*['"]?)\Q$ref\E(['"]?)}{$1$newname$2}gi);
                               $rewrites += $numchg;
                           }
                       }
                       if ($rewrites) {
                           my $saveresult; 
                           my $url = &Apache::lonnet::store_edited_file($container,$content,$udom,$uname,\$saveresult);
                           if ($url eq $container) {
                               my ($fname) = ($container =~ m{/([^/]+)$});
                               $output .= '<p>'.&mt('Rewrote [quant,_1,link] as [quant,_1,absolute link] in [_2].',
                                               $count,'<span class="LC_filename">'.
                                               $fname.'</span>').'</p>';
                           } else {
                               $output .= '<p class="LC_error">'.
                                          &mt('Error: could not update links in [_1].',
                                          '<span class="LC_filename">'.
                                          $container.'</span>').'</p>';
   
                           }
                       }
                   }
               }
         } else {          } else {
             &logthis('Failed to parse '.$container.              &logthis('Failed to parse '.$container.
                      ' to modify references: '.$parse_result);                       ' to modify references: '.$parse_result);
         }          }
     }      }
     return $output;      if (wantarray) {
           return ($output,$count,$codebasecount);
       } else {
           return $output;
       }
 }  }
   
 sub check_for_existing {  sub check_for_existing {
Line 9657  sub check_for_upload { Line 10921  sub check_for_upload {
                     if ($currsize < $filesize) {                      if ($currsize < $filesize) {
                         my $extra = $filesize - $currsize;                          my $extra = $filesize - $currsize;
                         if (($current_disk_usage + $extra) > $disk_quota) {                          if (($current_disk_usage + $extra) > $disk_quota) {
                             my $msg = '<span class="LC_error">'.                              my $msg = '<p class="LC_warning">'.
                                       &mt('Unable to upload [_1]. (size = [_2] kilobytes). Disk quota will be exceeded if existing (smaller) file with same name (size = [_3] kilobytes) is replaced.',                                        &mt('Unable to upload [_1]. (size = [_2] kilobytes). Disk quota will be exceeded if existing (smaller) file with same name (size = [_3] kilobytes) is replaced.',
                                           '<span class="LC_filename">'.$fname.'</span>',$filesize,$currsize).'</span>'.                                            '<span class="LC_filename">'.$fname.'</span>',$filesize,$currsize).'</p>'.
                                       '<br />'.&mt('Disk quota is [_1] kilobytes. Your current disk usage is [_2] kilobytes.',                                        '<p>'.&mt('Disk quota is [_1] kilobytes. Your current disk usage is [_2] kilobytes.',
                                                    $disk_quota,$current_disk_usage);                                                     $disk_quota,$current_disk_usage).'</p>';
                             return ('will_exceed_quota',$msg);                              return ('will_exceed_quota',$msg);
                         }                          }
                     }                      }
Line 9670  sub check_for_upload { Line 10934  sub check_for_upload {
         }          }
     }      }
     if (($current_disk_usage + $filesize) > $disk_quota){      if (($current_disk_usage + $filesize) > $disk_quota){
         my $msg = '<span class="LC_error">'.          my $msg = '<p class="LC_warning">'.
                 &mt('Unable to upload [_1]. (size = [_2] kilobytes). Disk quota will be exceeded.','<span class="LC_filename">'.$fname.'</span>',$filesize).'</span>'.                  &mt('Unable to upload [_1]. (size = [_2] kilobytes). Disk quota will be exceeded.','<span class="LC_filename">'.$fname.'</span>',$filesize).'</p>'.
                   '<br />'.&mt('Disk quota is [_1] kilobytes. Your current disk usage is [_2] kilobytes.',$disk_quota,$current_disk_usage);                    '<br />'.&mt('Disk quota is [_1] kilobytes. Your current disk usage is [_2] kilobytes.',$disk_quota,$current_disk_usage);
         return ('will_exceed_quota',$msg);          return ('will_exceed_quota',$msg);
     } elsif ($found_file) {      } elsif ($found_file) {
         if ($locked_file) {          if ($locked_file) {
             my $msg = '<span class="LC_error">';              my $msg = '<p class="LC_warning">';
             $msg .= &mt('Unable to upload [_1]. A locked file by that name was found in [_2].','<span class="LC_filename">'.$fname.'</span>','<span class="LC_filename">'.$port_path.$env{'form.currentpath'}.'</span>');              $msg .= &mt('Unable to upload [_1]. A locked file by that name was found in [_2].','<span class="LC_filename">'.$fname.'</span>','<span class="LC_filename">'.$port_path.$env{'form.currentpath'}.'</span>');
             $msg .= '</span><br />';              $msg .= '</p>';
             $msg .= &mt('You will be able to rename or delete existing [_1] after a grade has been assigned.','<span class="LC_filename">'.$fname.'</span>');              $msg .= &mt('You will be able to rename or delete existing [_1] after a grade has been assigned.','<span class="LC_filename">'.$fname.'</span>');
             return ('file_locked',$msg);              return ('file_locked',$msg);
         } else {          } else {
             my $msg = '<span class="LC_error">';              my $msg = '<p class="LC_error">';
             $msg .= &mt(' A file by that name: [_1] was found in [_2].','<span class="LC_filename">'.$fname.'</span>',$port_path.$env{'form.currentpath'});              $msg .= &mt(' A file by that name: [_1] was found in [_2].','<span class="LC_filename">'.$fname.'</span>',$port_path.$env{'form.currentpath'});
             $msg .= '</span>';              $msg .= '</p>';
             return ('existingfile',$msg);              return ('existingfile',$msg);
         }          }
     }      }
Line 9744  sub is_archive_file { Line 11008  sub is_archive_file {
 }  }
   
 sub decompress_form {  sub decompress_form {
     my ($mimetype,$archiveurl,$action,$noextract,$hiddenelements) = @_;      my ($mimetype,$archiveurl,$action,$noextract,$hiddenelements,$dirlist) = @_;
     my %lt = &Apache::lonlocal::texthash (      my %lt = &Apache::lonlocal::texthash (
         this => 'This file is an archive file.',          this => 'This file is an archive file.',
           camt => 'This file is a Camtasia archive file.',
           itsc => 'Its contents are as follows:',
         youm => 'You may wish to extract its contents.',          youm => 'You may wish to extract its contents.',
         camt => 'Extraction of contents is recommended for Camtasia zip files.',  
         perm => 'Permanently remove archive file after extraction of contents?',  
         extr => 'Extract contents',          extr => 'Extract contents',
           auto => 'LON-CAPA can process the files automatically, or you can decide how each should be handled.',
           proa => 'Process automatically?',
         yes  => 'Yes',          yes  => 'Yes',
         no   => 'No',          no   => 'No',
           fold => 'Title for folder containing movie',
           movi => 'Title for page containing embedded movie', 
     );      );
     my $output = '<p>'.$lt{'this'}.' '.$lt{'youm'}.'<br />';      my $fileloc = &Apache::lonnet::filelocation(undef,$archiveurl);
       my ($is_camtasia,$topdir,%toplevel,@paths);
       my $info = &list_archive_contents($fileloc,\@paths);
       if (@paths) {
           foreach my $path (@paths) {
               $path =~ s{^/}{};
               if ($path =~ m{^([^/]+)/$}) {
                   $topdir = $1;
               }
               if ($path =~ m{^([^/]+)/}) {
                   $toplevel{$1} = $path;
               } else {
                   $toplevel{$path} = $path;
               }
           }
       }
     if ($mimetype =~ m{^application/(x\-)?(compressed|zip)}) {      if ($mimetype =~ m{^application/(x\-)?(compressed|zip)}) {
         $output .= $lt{'camt'};          my @camtasia6 = ("$topdir/","$topdir/index.html",
                           "$topdir/media/",
                           "$topdir/media/$topdir.mp4",
                           "$topdir/media/FirstFrame.png",
                           "$topdir/media/player.swf",
                           "$topdir/media/swfobject.js",
                           "$topdir/media/expressInstall.swf");
           my @camtasia8 = ("$topdir/","$topdir/$topdir.html",
                            "$topdir/$topdir.mp4",
                            "$topdir/$topdir\_config.xml",
                            "$topdir/$topdir\_controller.swf",
                            "$topdir/$topdir\_embed.css",
                            "$topdir/$topdir\_First_Frame.png",
                            "$topdir/$topdir\_player.html",
                            "$topdir/$topdir\_Thumbnails.png",
                            "$topdir/playerProductInstall.swf",
                            "$topdir/scripts/",
                            "$topdir/scripts/config_xml.js",
                            "$topdir/scripts/handlebars.js",
                            "$topdir/scripts/jquery-1.7.1.min.js",
                            "$topdir/scripts/jquery-ui-1.8.15.custom.min.js",
                            "$topdir/scripts/modernizr.js",
                            "$topdir/scripts/player-min.js",
                            "$topdir/scripts/swfobject.js",
                            "$topdir/skins/",
                            "$topdir/skins/configuration_express.xml",
                            "$topdir/skins/express_show/",
                            "$topdir/skins/express_show/player-min.css",
                            "$topdir/skins/express_show/spritesheet.png");
           my @diffs = &compare_arrays(\@paths,\@camtasia6);
           if (@diffs == 0) {
               $is_camtasia = 6;
           } else {
               @diffs = &compare_arrays(\@paths,\@camtasia8);
               if (@diffs == 0) {
                   $is_camtasia = 8;
               }
           }
     }      }
     $output .= '</p>';      my $output;
     $output .= <<"START";      if ($is_camtasia) {
 <div id="uploadfileresult">          $output = <<"ENDCAM";
   <form name="uploaded_decompress" action="$action" method="post">  <script type="text/javascript" language="Javascript">
   <input type="hidden" name="archiveurl" value="$archiveurl" />  // <![CDATA[
 START  
   function camtasiaToggle() {
       for (var i=0; i<document.uploaded_decompress.autoextract_camtasia.length; i++) {
           if (document.uploaded_decompress.autoextract_camtasia[i].checked) {
               if (document.uploaded_decompress.autoextract_camtasia[i].value == $is_camtasia) {
   
                   document.getElementById('camtasia_titles').style.display='block';
               } else {
                   document.getElementById('camtasia_titles').style.display='none';
               }
           }
       }
       return;
   }
   
   // ]]>
   </script>
   <p>$lt{'camt'}</p>
   ENDCAM
       } else {
           $output = '<p>'.$lt{'this'};
           if ($info eq '') {
               $output .= ' '.$lt{'youm'}.'</p>'."\n";
           } else {
               $output .= ' '.$lt{'itsc'}.'</p>'."\n".
                          '<div><pre>'.$info.'</pre></div>';
           }
       }
       $output .= '<form name="uploaded_decompress" action="'.$action.'" method="post">'."\n";
       my $duplicates;
       my $num = 0;
       if (ref($dirlist) eq 'ARRAY') {
           foreach my $item (@{$dirlist}) {
               if (ref($item) eq 'ARRAY') {
                   if (exists($toplevel{$item->[0]})) {
                       $duplicates .= 
                           &start_data_table_row().
                           '<td><label><input type="radio" name="archive_overwrite_'.$num.'" '.
                           'value="0" checked="checked" />'.&mt('No').'</label>'.
                           '&nbsp;<label><input type="radio" name="archive_overwrite_'.$num.'" '.
                           'value="1" />'.&mt('Yes').'</label>'.
                           '<input type="hidden" name="archive_overwrite_name_'.$num.'" value="'.$item->[0].'" /></td>'."\n".
                           '<td>'.$item->[0].'</td>';
                       if ($item->[2]) {
                           $duplicates .= '<td>'.&mt('Directory').'</td>';
                       } else {
                           $duplicates .= '<td>'.&mt('File').'</td>';
                       }
                       $duplicates .= '<td>'.$item->[3].'</td>'.
                                      '<td>'.
                                      &Apache::lonlocal::locallocaltime($item->[4]).
                                      '</td>'.
                                      &end_data_table_row();
                       $num ++;
                   }
               }
           }
       }
       my $itemcount;
       if (@paths > 0) {
           $itemcount = scalar(@paths);
       } else {
           $itemcount = 1;
       }
       if ($is_camtasia) {
           $output .= $lt{'auto'}.'<br />'.
                      '<span class="LC_nobreak">'.$lt{'proa'}.'<label>'.
                      '<input type="radio" name="autoextract_camtasia" value="'.$is_camtasia.'" onclick="javascript:camtasiaToggle();" checked="checked" />'.
                      $lt{'yes'}.'</label>&nbsp;<label>'.
                      '<input type="radio" name="autoextract_camtasia" value="0" onclick="javascript:camtasiaToggle();" />'.
                      $lt{'no'}.'</label></span><br />'.
                      '<div id="camtasia_titles" style="display:block">'.
                      &Apache::lonhtmlcommon::start_pick_box().
                      &Apache::lonhtmlcommon::row_title($lt{'fold'}).
                      '<input type="textbox" name="camtasia_foldername" value="'.$env{'form.comment'}.'" />'."\n".
                      &Apache::lonhtmlcommon::row_closure().
                      &Apache::lonhtmlcommon::row_title($lt{'movi'}).
                      '<input type="textbox" name="camtasia_moviename" value="" />'."\n".
                      &Apache::lonhtmlcommon::row_closure(1).
                      &Apache::lonhtmlcommon::end_pick_box().
                      '</div>';
       }
       $output .= 
           '<input type="hidden" name="archive_overwrite_total" value="'.$num.'" />'.
           '<input type="hidden" name="archive_itemcount" value="'.$itemcount.'" />'.
           "\n";
       if ($duplicates ne '') {
           $output .= '<p><span class="LC_warning">'.
                      &mt('Warning: decompression of the archive will overwrite the following items which already exist:').'</span><br />'.  
                      &start_data_table().
                      &start_data_table_header_row().
                      '<th>'.&mt('Overwrite?').'</th>'.
                      '<th>'.&mt('Name').'</th>'.
                      '<th>'.&mt('Type').'</th>'.
                      '<th>'.&mt('Size').'</th>'.
                      '<th>'.&mt('Last modified').'</th>'.
                      &end_data_table_header_row().
                      $duplicates.
                      &end_data_table().
                      '</p>';
       }
       $output .= '<input type="hidden" name="archiveurl" value="'.$archiveurl.'" />'."\n";
     if (ref($hiddenelements) eq 'HASH') {      if (ref($hiddenelements) eq 'HASH') {
         foreach my $hidden (sort(keys(%{$hiddenelements}))) {          foreach my $hidden (sort(keys(%{$hiddenelements}))) {
             $output .= '<input type="hidden" name="'.$hidden.'" value="'.$hiddenelements->{$hidden}.'" />'."\n";              $output .= '<input type="hidden" name="'.$hidden.'" value="'.$hiddenelements->{$hidden}.'" />'."\n";
         }          }
     }      }
     $output .= <<"END";      $output .= <<"END";
 <span class="LC_nobreak">$lt{'perm'}&nbsp;  <br />
 <label><input type="radio" name="archivedelete" value="0" checked="checked" />$lt{'no'}</label>&nbsp;&nbsp;  
 <label><input type="radio" name="archivedelete" value="1" />$lt{'yes'}</label></span><br />  
 <input type="submit" name="decompress" value="$lt{'extr'}" />  <input type="submit" name="decompress" value="$lt{'extr'}" />
 </form>  </form>
 $noextract  $noextract
 </div>  
 END  END
     return $output;      return $output;
 }  }
   
   sub decompression_utility {
       my ($program) = @_;
       my @utilities = ('tar','gunzip','bunzip2','unzip'); 
       my $location;
       if (grep(/^\Q$program\E$/,@utilities)) { 
           foreach my $dir ('/bin/','/usr/bin/','/usr/local/bin/','/sbin/',
                            '/usr/sbin/') {
               if (-x $dir.$program) {
                   $location = $dir.$program;
                   last;
               }
           }
       }
       return $location;
   }
   
   sub list_archive_contents {
       my ($file,$pathsref) = @_;
       my (@cmd,$output);
       my $needsregexp;
       if ($file =~ /\.zip$/) {
           @cmd = (&decompression_utility('unzip'),"-l");
           $needsregexp = 1;
       } elsif (($file =~ m/\.tar\.gz$/) ||
                ($file =~ /\.tgz$/)) {
           @cmd = (&decompression_utility('tar'),"-ztf");
       } elsif ($file =~ /\.tar\.bz2$/) {
           @cmd = (&decompression_utility('tar'),"-jtf");
       } elsif ($file =~ m|\.tar$|) {
           @cmd = (&decompression_utility('tar'),"-tf");
       }
       if (@cmd) {
           undef($!);
           undef($@);
           if (open(my $fh,"-|", @cmd, $file)) {
               while (my $line = <$fh>) {
                   $output .= $line;
                   chomp($line);
                   my $item;
                   if ($needsregexp) {
                       ($item) = ($line =~ /^\s*\d+\s+[\d\-]+\s+[\d:]+\s*(.+)$/); 
                   } else {
                       $item = $line;
                   }
                   if ($item ne '') {
                       unless (grep(/^\Q$item\E$/,@{$pathsref})) {
                           push(@{$pathsref},$item);
                       } 
                   }
               }
               close($fh);
           }
       }
       return $output;
   }
   
 sub decompress_uploaded_file {  sub decompress_uploaded_file {
     my ($file,$dir) = @_;      my ($file,$dir) = @_;
     &Apache::lonnet::appenv({'cgi.file' => $file});      &Apache::lonnet::appenv({'cgi.file' => $file});
Line 9799  sub decompress_uploaded_file { Line 11273  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) = @_;
     my ($dir,$error,$warning,$output);      my ($dir,$error,$warning,$output);
     if ($file !~ /\.(zip|tar|bz2|gz|tar.gz|tar.bz2|tgz)$/) {      if ($file !~ /\.(zip|tar|bz2|gz|tar.gz|tar.bz2|tgz)$/i) {
         $error = &mt('File name not a supported archive file type.').          $error = &mt('Filename not a supported archive file type.').
                  '<br />'.&mt('File name should end with one of: [_1].',                   '<br />'.&mt('Filename should end with one of: [_1].',
                               '.zip, .tar, .bz2, .gz, .tar.gz, .tar.bz2, .tgz');                                '.zip, .tar, .bz2, .gz, .tar.gz, .tar.bz2, .tgz');
     } else {      } else {
         my $docuhome = &Apache::lonnet::homeserver($docuname,$docudom);          my $docuhome = &Apache::lonnet::homeserver($docuname,$docudom);
Line 9810  sub process_decompression { Line 11284  sub process_decompression {
         } else {          } else {
             my @ids=&Apache::lonnet::current_machine_ids();              my @ids=&Apache::lonnet::current_machine_ids();
             my $currdir = "$dir_root/$destination";              my $currdir = "$dir_root/$destination";
             my ($currdirlistref,$currlisterror) =  
                 &Apache::lonnet::dirlist($currdir,$docudom,$docuname,1);  
             if (grep(/^\Q$docuhome\E$/,@ids)) {              if (grep(/^\Q$docuhome\E$/,@ids)) {
                 $dir = &LONCAPA::propath($docudom,$docuname).                  $dir = &LONCAPA::propath($docudom,$docuname).
                        "$dir_root/$destination";                         "$dir_root/$destination";
Line 9822  sub process_decompression { Line 11294  sub process_decompression {
                     $error = &mt('Archive file not found.');                      $error = &mt('Archive file not found.');
                 }                  }
             }              }
             if ($dir eq '') {              my (@to_overwrite,@to_skip);
               if ($env{'form.archive_overwrite_total'} > 0) {
                   my $total = $env{'form.archive_overwrite_total'};
                   for (my $i=0; $i<$total; $i++) {
                       if ($env{'form.archive_overwrite_'.$i} == 1) {
                           push(@to_overwrite,$env{'form.archive_overwrite_name_'.$i});
                       } elsif ($env{'form.archive_overwrite_'.$i} == 0) {
                           push(@to_skip,$env{'form.archive_overwrite_name_'.$i});
                       }
                   }
               }
               my $numskip = scalar(@to_skip);
               if (($numskip > 0) && 
                   ($numskip == $env{'form.archive_itemcount'})) {
                   $warning = &mt('All items in the archive file already exist, and no overwriting of existing files has been requested.');         
               } elsif ($dir eq '') {
                 $error = &mt('Directory containing archive file unavailable.');                  $error = &mt('Directory containing archive file unavailable.');
             } elsif (!$error) {              } elsif (!$error) {
                 my ($decompressed,$display) = &decompress_uploaded_file($file,$dir);                  my ($decompressed,$display);
                   if ($numskip > 0) {
                       my $tempdir = time.'_'.$$.int(rand(10000));
                       mkdir("$dir/$tempdir",0755);
                       system("mv $dir/$file $dir/$tempdir/$file");
                       ($decompressed,$display) = 
                           &decompress_uploaded_file($file,"$dir/$tempdir");
                       foreach my $item (@to_skip) {
                           if (($item ne '') && ($item !~ /\.\./)) {
                               if (-f "$dir/$tempdir/$item") { 
                                   unlink("$dir/$tempdir/$item");
                               } elsif (-d "$dir/$tempdir/$item") {
                                   system("rm -rf $dir/$tempdir/$item");
                               }
                           }
                       }
                       system("mv $dir/$tempdir/* $dir");
                       rmdir("$dir/$tempdir");   
                   } else {
                       ($decompressed,$display) = 
                           &decompress_uploaded_file($file,$dir);
                   }
                 if ($decompressed eq 'ok') {                  if ($decompressed eq 'ok') {
                     $output = &mt('Files extracted successfully from archive.').'<br />';                      $output = '<p class="LC_info">'.
                                 &mt('Files extracted successfully from archive.').
                                 '</p>'."\n";
                     my ($warning,$result,@contents);                      my ($warning,$result,@contents);
                     my ($newdirlistref,$newlisterror) =                      my ($newdirlistref,$newlisterror) =
                         &Apache::lonnet::dirlist($currdir,$docudom,                          &Apache::lonnet::dirlist($currdir,$docudom,
                                                  $docuname,1);                                                   $docuname,1);
                     my (%is_dir,%changes,@newitems);                      my (%is_dir,%changes,@newitems);
                     my $dirptr = 16384;                      my $dirptr = 16384;
                     if (ref($currdirlistref) eq 'ARRAY') {                      if (ref($newdirlistref) eq 'ARRAY') {
                         my @curritems;  
                         foreach my $dir_line (@{$currdirlistref}) {  
                             my ($item,$rest)=split(/\&/,$dir_line,2);  
                             unless ($item =~ /\.+$/) {  
                                 push(@curritems,$item);  
                             }  
                         }  
                         if (ref($newdirlistref) eq 'ARRAY') {  
                             foreach my $dir_line (@{$newdirlistref}) {  
                                 my ($item,undef,undef,$testdir)=split(/\&/,$dir_line,4);  
                                 unless ($item =~ /^\.+$/) {  
                                     if ($dirptr&$testdir) {  
                                         $is_dir{$item} = 1;  
                                     }  
                                     push(@newitems,$item);  
                                 }  
                             }  
                             my @diffs = &compare_arrays(\@curritems,\@newitems);  
                             if (@diffs > 0) {  
                                foreach my $item (@diffs) {  
                                    $changes{$item} = 1;  
                                }  
                             }  
                         }  
                     } elsif (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 =~ /\.+$/) {                              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 9879  sub process_decompression { Line 11365  sub process_decompression {
                         }                          }
                     }                      }
                     if (@contents > 0) {                      if (@contents > 0) {
                           my $wantform;
                           unless ($env{'form.autoextract_camtasia'}) {
                               $wantform = 1;
                           }
                         my (%children,%parent,%dirorder,%titles);                          my (%children,%parent,%dirorder,%titles);
                         my $wantform = 1;  
                         my ($count,$datatable) = &get_extracted($docudom,$docuname,                          my ($count,$datatable) = &get_extracted($docudom,$docuname,
                                                                 $currdir,\%is_dir,                                                                  $currdir,\%is_dir,
                                                                 \%children,\%parent,                                                                  \%children,\%parent,
Line 9889  sub process_decompression { Line 11378  sub process_decompression {
                         if ($datatable ne '') {                          if ($datatable ne '') {
                             $output .= &archive_options_form('decompressed',$datatable,                              $output .= &archive_options_form('decompressed',$datatable,
                                                              $count,$hiddenelem);                                                               $count,$hiddenelem);
                             my $startcount = 4;                              my $startcount = 6;
                             $output .= &archive_javascript($startcount,$count,                              $output .= &archive_javascript($startcount,$count,
                                                            \%titles,\%children);                                                             \%titles,\%children);
                         }                          }
                           if ($env{'form.autoextract_camtasia'}) {
                               my $version = $env{'form.autoextract_camtasia'};
                               my %displayed;
                               my $total = 1;
                               $env{'form.archive_directory'} = [];
                               foreach my $i (sort { $a <=> $b } keys(%dirorder)) {
                                   my $path = join('/',map { $titles{$_}; } @{$dirorder{$i}});
                                   $path =~ s{/$}{};
                                   my $item;
                                   if ($path ne '') {
                                       $item = "$path/$titles{$i}";
                                   } else {
                                       $item = $titles{$i};
                                   }
                                   $env{'form.archive_content_'.$i} = "$dir_root/$destination/$item";
                                   if ($item eq $contents[0]) {
                                       push(@{$env{'form.archive_directory'}},$i);
                                       $env{'form.archive_'.$i} = 'display';
                                       $env{'form.archive_title_'.$i} = $env{'form.camtasia_foldername'};
                                       $displayed{'folder'} = $i;
                                   } elsif ((($item eq "$contents[0]/index.html") && ($version == 6)) ||
                                            (($item eq "$contents[0]/$contents[0]".'.html') && ($version == 8))) { 
                                       $env{'form.archive_'.$i} = 'display';
                                       $env{'form.archive_title_'.$i} = $env{'form.camtasia_moviename'};
                                       $displayed{'web'} = $i;
                                   } else {
                                       if ((($item eq "$contents[0]/media") && ($version == 6)) ||
                                           ((($item eq "$contents[0]/scripts") || ($item eq "$contents[0]/skins") ||
                                                ($item eq "$contents[0]/skins/express_show")) && ($version == 8))) {
                                           push(@{$env{'form.archive_directory'}},$i);
                                       }
                                       $env{'form.archive_'.$i} = 'dependency';
                                   }
                                   $total ++;
                               }
                               for (my $i=1; $i<$total; $i++) {
                                   next if ($i == $displayed{'web'});
                                   next if ($i == $displayed{'folder'});
                                   $env{'form.archive_dependent_on_'.$i} = $displayed{'web'};
                               }
                               $env{'form.phase'} = 'decompress_cleanup';
                               $env{'form.archivedelete'} = 1;
                               $env{'form.archive_count'} = $total-1;
                               $output .=
                                   &process_extracted_files('coursedocs',$docudom,
                                                            $docuname,$destination,
                                                            $dir_root,$hiddenelem);
                           }
                     } else {                      } else {
                         $warning = &mt('No new items extracted from archive file.');                          $warning = &mt('No new items extracted from archive file.');
                     }                      }
Line 10018  sub archive_row { Line 11555  sub archive_row {
     my $offset = 0;      my $offset = 0;
     foreach my $action ('display','dependency','discard') {      foreach my $action ('display','dependency','discard') {
         $offset ++;          $offset ++;
           if ($action ne 'display') {
               $offset ++;
           }  
         $output .= '<td><span class="LC_nobreak">'.          $output .= '<td><span class="LC_nobreak">'.
                    '<label><input type="radio" name="archive_'.$count.                     '<label><input type="radio" name="archive_'.$count.
                    '" id="archive_'.$action.'_'.$count.'" value="'.$action.'"';                     '" id="archive_'.$action.'_'.$count.'" value="'.$action.'"';
Line 10063  sub archive_row { Line 11603  sub archive_row {
 }  }
   
 sub archive_options_form {  sub archive_options_form {
     my ($form,$output,$count,$hiddenelem) = @_;      my ($form,$display,$count,$hiddenelem) = @_;
     return '<form name="'.$form.'" method="post" action="">'."\n".      my %lt = &Apache::lonlocal::texthash(
            '<input type="hidden" name="phase" value="decompress_cleanup" />'."\n".                 perm => 'Permanently remove archive file?',
                     '<p>'.                 hows => 'How should each extracted item be incorporated in the course?',
                     &mt('How should each item be incorporated in the course?').                 cont => 'Content actions for all',
                     '</p>'.                 addf => 'Add as folder/file',
                     '<div class="LC_columnSection"><fieldset>'.                 incd => 'Include as dependency for a displayed file',
                     '<legend>'.&mt('Content actions for all').'</legend>'.                 disc => 'Discard',
                     '<input type="button" value="'.&mt('Add as folder/file').'" '.                 no   => 'No',
                     'onclick="javascript:checkAll(document.'.$form.",'display'".')" />'.                 yes  => 'Yes',
                     '&nbsp;&nbsp;<input type="button" value="'.&mt('Include as dependency for a displayed file').'"'.                 save => 'Save',
                     ' onclick="javascript:checkAll(document.'.$form.",'dependency'".')" />'.      );
                     '&nbsp;&nbsp;<input type="button" value="'.&mt('Discard').'"'.      my $output = <<"END";
                     ' onclick="javascript:checkAll(document.'.$form.",'discard'".')" />'.  <form name="$form" method="post" action="">
                      '</fieldset></div>'.  <p><span class="LC_nobreak">$lt{'perm'}&nbsp;
   <label>
     <input type="radio" name="archivedelete" value="0" checked="checked" />$lt{'no'}
   </label>
   &nbsp;
   <label>
     <input type="radio" name="archivedelete" value="1" />$lt{'yes'}</label>
   </span>
   </p>
   <input type="hidden" name="phase" value="decompress_cleanup" />
   <br />$lt{'hows'}
   <div class="LC_columnSection">
     <fieldset>
       <legend>$lt{'cont'}</legend>
       <input type="button" value="$lt{'addf'}" onclick="javascript:checkAll(document.$form,'display');" /> 
       &nbsp;&nbsp;<input type="button" value="$lt{'incd'}" onclick="javascript:checkAll(document.$form,'dependency');" />
       &nbsp;&nbsp;<input type="button" value="$lt{'disc'}" onclick="javascript:checkAll(document.$form,'discard');" />
     </fieldset>
   </div>
   END
       return $output.
            &start_data_table()."\n".             &start_data_table()."\n".
            $output."\n".             $display."\n".
            &end_data_table()."\n".             &end_data_table()."\n".
            '<input type="hidden" name="archive_count" value="'.$count.'" />'.             '<input type="hidden" name="archive_count" value="'.$count.'" />'.
            $hiddenelem.             $hiddenelem.
            '<br /><input type="submit" name="archive_submit" value="'.&mt('Save').'" />'.             '<br /><input type="submit" name="archive_submit" value="'.$lt{'save'}.'" />'.
            '</form>';             '</form>';
 }  }
   
Line 10177  function dependencyCheck(form,count,offs Line 11737  function dependencyCheck(form,count,offs
             document.getElementById('arc_depon_'+count).style.display='block';               document.getElementById('arc_depon_'+count).style.display='block'; 
             form.elements[depitem].options.length = 0;              form.elements[depitem].options.length = 0;
             form.elements[depitem].options[0] = new Option('Select','',true,true);              form.elements[depitem].options[0] = new Option('Select','',true,true);
             for (var i=1; i<count; i++) {              for (var i=1; i<=numitems; i++) {
                   if (i == count) {
                       continue;
                   }
                 var startelement = $startcount + (i-1) * 7;                  var startelement = $startcount + (i-1) * 7;
                 for (var j=1; j<6; j++) {                  for (var j=1; j<6; j++) {
                     if ((j != 2) && (j!= 4)) {                      if ((j != 2) && (j!= 4)) {
Line 10204  function dependencyCheck(form,count,offs Line 11767  function dependencyCheck(form,count,offs
   
 function propagateSelect(form,count,offset) {  function propagateSelect(form,count,offset) {
     if (count > 0) {      if (count > 0) {
         var item = (2+offset+$startcount)+7*(count-1);          var item = (1+offset+$startcount)+7*(count-1);
         var picked = form.elements[item].options[form.elements[item].selectedIndex].value;           var picked = form.elements[item].options[form.elements[item].selectedIndex].value; 
         if (Object.prototype.toString.call(parents[count]) === '[object Array]') {          if (Object.prototype.toString.call(parents[count]) === '[object Array]') {
             if (parents[count].length > 0) {              if (parents[count].length > 0) {
Line 10218  function propagateSelect(form,count,offs Line 11781  function propagateSelect(form,count,offs
   
 function containerSelect(form,count,offset,picked) {  function containerSelect(form,count,offset,picked) {
     if (count > 0) {      if (count > 0) {
         var item = (1+offset+$startcount)+7*(count-1);          var item = (offset+$startcount)+7*(count-1);
         if (form.elements[item].type == 'radio') {          if (form.elements[item].type == 'radio') {
             if (form.elements[item].value == 'dependency') {              if (form.elements[item].value == 'dependency') {
                 if (form.elements[item+1].type == 'select-one') {                  if (form.elements[item+1].type == 'select-one') {
Line 10273  sub process_extracted_files { Line 11836  sub process_extracted_files {
     return unless ($numitems);      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);          %folders,%containers,%mapinner,%prompttofetch);
     my $docuhome = &Apache::lonnet::homeserver($docuname,$docudom);      my $docuhome = &Apache::lonnet::homeserver($docuname,$docudom);
     if (grep(/^\Q$docuhome\E$/,@ids)) {      if (grep(/^\Q$docuhome\E$/,@ids)) {
         $prefix = &LONCAPA::propath($docudom,$docuname);          $prefix = &LONCAPA::propath($docudom,$docuname);
Line 10290  sub process_extracted_files { Line 11853  sub process_extracted_files {
     if ($env{'form.folderpath'}) {      if ($env{'form.folderpath'}) {
         my @items = split('&',$env{'form.folderpath'});          my @items = split('&',$env{'form.folderpath'});
         $folders{'0'} = $items[-2];          $folders{'0'} = $items[-2];
         $containers{'0'}='sequence';          if ($env{'form.folderpath'} =~ /\:1$/) {
     } elsif ($env{'form.pagepath'}) {              $containers{'0'}='page';
         my @items = split('&',$env{'form.pagepath'});          } else {  
         $folders{'0'} = $items[-2];              $containers{'0'}='sequence';
         $containers{'0'}='page';          }
     }      }
     my @archdirs = &get_env_multiple('form.archive_directory');      my @archdirs = &get_env_multiple('form.archive_directory');
     if ($numitems) {      if ($numitems) {
Line 10309  sub process_extracted_files { Line 11872  sub process_extracted_files {
             }              }
         }          }
     }      }
     my ($output,%children,%parent,%titles,%dirorder);      my ($output,%children,%parent,%titles,%dirorder,$result);
     if (keys(%toplevelitems) > 0) {      if (keys(%toplevelitems) > 0) {
         my @contents = sort(keys(%toplevelitems));          my @contents = sort(keys(%toplevelitems));
         (my $count,undef) = &get_extracted($docudom,$docuname,$currdir,\%is_dir,\%children,          (my $count,undef) = &get_extracted($docudom,$docuname,$currdir,\%is_dir,\%children,
                                            \%parent,\@contents,\%dirorder,\%titles);                                             \%parent,\@contents,\%dirorder,\%titles);
     }      }
     my (%referrer,%orphaned,%todelete,%newdest,%newseqid);      my (%referrer,%orphaned,%todelete,%todeletedir,%newdest,%newseqid);
     if ($numitems) {      if ($numitems) {
         for (my $i=1; $i<=$numitems; $i++) {          for (my $i=1; $i<=$numitems; $i++) {
               next if ($env{'form.archive_'.$i} eq 'dependency');
             my $path = $env{'form.archive_content_'.$i};              my $path = $env{'form.archive_content_'.$i};
             if ($path =~ /^\Q$pathtocheck\E/) {              if ($path =~ /^\Q$pathtocheck\E/) {
                 if ($env{'form.archive_'.$i} eq 'discard') {                  if ($env{'form.archive_'.$i} eq 'discard') {
                     if ($prefix ne '' && $path ne '') {                      if ($prefix ne '' && $path ne '') {
                         if (-e $prefix.$path) {                          if (-e $prefix.$path) {
                             $todelete{$prefix.$path} = 1;                              if ((@archdirs > 0) && 
                                   (grep(/^\Q$i\E$/,@archdirs))) {
                                   $todeletedir{$prefix.$path} = 1;
                               } else {
                                   $todelete{$prefix.$path} = 1;
                               }
                         }                          }
                     }                      }
                 } elsif ($env{'form.archive_'.$i} eq 'display') {                  } elsif ($env{'form.archive_'.$i} eq 'display') {
Line 10363  sub process_extracted_files { Line 11932  sub process_extracted_files {
                             my ($outtext,$errtext) =                              my ($outtext,$errtext) =
                                 &LONCAPA::map::storemap('/uploaded/'.$docudom.'/'.                                  &LONCAPA::map::storemap('/uploaded/'.$docudom.'/'.
                                                         $docuname.'/'.$folders{$outer}.                                                          $docuname.'/'.$folders{$outer}.
                                                         '.'.$containers{$outer},1);                                                          '.'.$containers{$outer},1,1);
                             $newseqid{$i} = $newidx;                              $newseqid{$i} = $newidx;
                               unless ($errtext) {
                                   $result .=  '<li>'.&mt('Folder: [_1] added to course',$docstitle).'</li>'."\n";
                               }
                         }                          }
                     } else {                      } else {
                         if ($context eq 'coursedocs') {                          if ($context eq 'coursedocs') {
Line 10381  sub process_extracted_files { Line 11953  sub process_extracted_files {
                             if (-e "$prefix$dir/$docstype/$mapinner{$outer}/$newidx") {                              if (-e "$prefix$dir/$docstype/$mapinner{$outer}/$newidx") {
                                 system("mv $prefix$path $prefix$dir/$docstype/$mapinner{$outer}/$newidx/$title");                                  system("mv $prefix$path $prefix$dir/$docstype/$mapinner{$outer}/$newidx/$title");
                                 $newdest{$i} = "$prefix$dir/$docstype/$mapinner{$outer}/$newidx";                                  $newdest{$i} = "$prefix$dir/$docstype/$mapinner{$outer}/$newidx";
                                   unless ($ishome) {
                                       my $fetch = "$newdest{$i}/$title";
                                       $fetch =~ s/^\Q$prefix$dir\E//;
                                       $prompttofetch{$fetch} = 1;
                                   }
                             }                              }
                             $LONCAPA::map::resources[$newidx]=                              $LONCAPA::map::resources[$newidx]=
                                 $docstitle.':'.$url.':false:normal:res';                                  $docstitle.':'.$url.':false:normal:res';
Line 10388  sub process_extracted_files { Line 11965  sub process_extracted_files {
                             my ($outtext,$errtext)=                              my ($outtext,$errtext)=
                                 &LONCAPA::map::storemap('/uploaded/'.$docudom.'/'.                                  &LONCAPA::map::storemap('/uploaded/'.$docudom.'/'.
                                                         $docuname.'/'.$folders{$outer}.                                                          $docuname.'/'.$folders{$outer}.
                                                         '.'.$containers{$outer},1);                                                          '.'.$containers{$outer},1,1);
                               unless ($errtext) {
                                   if (-e "$prefix$dir/$docstype/$mapinner{$outer}/$newidx/$title") {
                                       $result .= '<li>'.&mt('File: [_1] added to course',$docstitle).'</li>'."\n";
                                   }
                               }
                         }                          }
                     }                      }
                 } elsif ($env{'form.archive_'.$i} eq 'dependency') {                  }
                     my ($title) = ($path =~ m{/([^/]+)$});              } else {
                     $referrer{$i} = $env{'form.archive_dependent_on_'.$i};                  $warning .= &mt('Item extracted from archive: [_1] has unexpected path.',$path).'<br />'; 
                     if ($env{'form.archive_'.$referrer{$i}} eq 'display') {              }
                         if (ref($dirorder{$i}) eq 'ARRAY') {          }
                             my ($itemidx,$fullpath);          for (my $i=1; $i<=$numitems; $i++) {
               next unless ($env{'form.archive_'.$i} eq 'dependency');
               my $path = $env{'form.archive_content_'.$i};
               if ($path =~ /^\Q$pathtocheck\E/) {
                   my ($title) = ($path =~ m{/([^/]+)$});
                   $referrer{$i} = $env{'form.archive_dependent_on_'.$i};
                   if ($env{'form.archive_'.$referrer{$i}} eq 'display') {
                       if (ref($dirorder{$i}) eq 'ARRAY') {
                           my ($itemidx,$fullpath,$relpath);
                           if (ref($dirorder{$referrer{$i}}) eq 'ARRAY') {
                               my $container = $dirorder{$referrer{$i}}->[-1];
                             for (my $j=0; $j<@{$dirorder{$i}}; $j++) {                              for (my $j=0; $j<@{$dirorder{$i}}; $j++) {
                                 if (ref($dirorder{$referrer{$i}}) eq 'ARRAY') {                                  if ($dirorder{$i}->[$j] eq $container) {
                                     my $container = $dirorder{$referrer{$i}}->[-1];                                      $itemidx = $j;
                                     for (my $j=0; $j<@{$dirorder{$i}}; $j++) {  
                                         if ($dirorder{$i}->[$j] eq $container) {  
                                             $itemidx = $j;  
                                         }  
                                     }  
                                 }                                  }
                             }                              }
                             if ($itemidx ne '') {                          }
                                 if (grep(/^\Q$referrer{$i}\E$/,@archdirs)) {                          if ($itemidx eq '') {
                                     if ($mapinner{$referrer{$i}}) {                              $itemidx =  0;
                                         $fullpath = "$prefix$dir/$docstype/$mapinner{$referrer{$i}}";                          } 
                                         for (my $j=$itemidx; $j<@{$dirorder{$i}}; $j++) {                          if (grep(/^\Q$referrer{$i}\E$/,@archdirs)) {
                                             if (grep(/^\Q$dirorder{$i}->[$j]\E$/,@archdirs)) {                              if ($mapinner{$referrer{$i}}) {
                                                 unless (defined($newseqid{$dirorder{$i}->[$j]})) {                                  $fullpath = "$prefix$dir/$docstype/$mapinner{$referrer{$i}}";
                                                     $fullpath .= '/'.$titles{$dirorder{$i}->[$j]};                                  for (my $j=$itemidx; $j<@{$dirorder{$i}}; $j++) {
                                                     if (!-e $fullpath) {                                      if (grep(/^\Q$dirorder{$i}->[$j]\E$/,@archdirs)) {
                                                         mkdir($fullpath,0755);                                          unless (defined($newseqid{$dirorder{$i}->[$j]})) {
                                                     }                                              $fullpath .= '/'.$titles{$dirorder{$i}->[$j]};
                                                 }                                              $relpath .= '/'.$titles{$dirorder{$i}->[$j]};
                                             } else {                                              if (!-e $fullpath) {
                                                 last;                                                  mkdir($fullpath,0755);
                                             }                                              }
                                         }                                          }
                                       } else {
                                           last;
                                     }                                      }
                                 } elsif ($newdest{$referrer{$i}}) {                                  }
                                     $fullpath = $newdest{$referrer{$i}};                              }
                                     for (my $j=$itemidx; $j<@{$dirorder{$i}}; $j++) {                          } elsif ($newdest{$referrer{$i}}) {
                                         if ($env{'form.archive_'.$dirorder{$i}->[$j]} eq 'discard') {                              $fullpath = $newdest{$referrer{$i}};
                                             $orphaned{$i} = $env{'form.archive_'.$dirorder{$i}->[$j]};                              for (my $j=$itemidx; $j<@{$dirorder{$i}}; $j++) {
                                             last;                                  if ($env{'form.archive_'.$dirorder{$i}->[$j]} eq 'discard') {
                                         } elsif (grep(/^\Q$dirorder{$i}->[$j]\E$/,@archdirs)) {                                      $orphaned{$i} = $env{'form.archive_'.$dirorder{$i}->[$j]};
                                             unless (defined($newseqid{$dirorder{$i}->[$j]})) {                                      last;
                                                 $fullpath .= '/'.$titles{$dirorder{$i}->[$j]};                                  } elsif (grep(/^\Q$dirorder{$i}->[$j]\E$/,@archdirs)) {
                                                 if (!-e $fullpath) {                                      unless (defined($newseqid{$dirorder{$i}->[$j]})) {
                                                     mkdir($fullpath,0755);                                          $fullpath .= '/'.$titles{$dirorder{$i}->[$j]};
                                                 }                                          $relpath .= '/'.$titles{$dirorder{$i}->[$j]};
                                             }                                          if (!-e $fullpath) {
                                         } else {                                              mkdir($fullpath,0755);
                                             last;  
                                         }                                          }
                                     }                                      }
                                   } else {
                                       last;
                                 }                                  }
                                 if ($fullpath ne '') {  
                                     system("mv $prefix$path $fullpath/$title");  
                                 }  
                             }                              }
                         }                          }
                     } elsif ($env{'form.archive_'.$referrer{$i}} eq 'discard') {                          if ($fullpath ne '') {
                         $warning .= &mt('[_1] is a dependency of [_2], which was discarded.',                              if (-e "$prefix$path") {
                                         $path,$env{'form.archive_content_'.$referrer{$i}}).'<br />';                                  system("mv $prefix$path $fullpath/$title");
                               }
                               if (-e "$fullpath/$title") {
                                   my $showpath;
                                   if ($relpath ne '') {
                                       $showpath = "$relpath/$title";
                                   } else {
                                       $showpath = "/$title";
                                   } 
                                   $result .= '<li>'.&mt('[_1] included as a dependency',$showpath).'</li>'."\n";
                               } 
                               unless ($ishome) {
                                   my $fetch = "$fullpath/$title";
                                   $fetch =~ s/^\Q$prefix$dir\E//; 
                                   $prompttofetch{$fetch} = 1;
                               }
                           }
                     }                      }
                   } elsif ($env{'form.archive_'.$referrer{$i}} eq 'discard') {
                       $warning .= &mt('[_1] is a dependency of [_2], which was discarded.',
                                       $path,$env{'form.archive_content_'.$referrer{$i}}).'<br />';
                 }                  }
             } else {              } else {
                 $warning .= &mt('Item extracted from archive: [_1] has unexpected path.',$path).'<br />';                   $warning .= &mt('Item extracted from archive: [_1] has unexpected path.',$path).'<br />'; 
Line 10459  sub process_extracted_files { Line 12065  sub process_extracted_files {
         if (keys(%todelete)) {          if (keys(%todelete)) {
             foreach my $key (keys(%todelete)) {              foreach my $key (keys(%todelete)) {
                 unlink($key);                  unlink($key);
                 unless ($ishome) {              }
                     #FIXME Need to notify homeserver to delete files.          }
                 }          if (keys(%todeletedir)) {
               foreach my $key (keys(%todeletedir)) {
                   rmdir($key);
               }
           }
           foreach my $dir (sort(keys(%is_dir))) {
               if (($pathtocheck ne '') && ($dir ne ''))  {
                   &cleanup_empty_dirs($prefix."$pathtocheck/$dir");
               }
           }
           if ($result ne '') {
               $output .= '<ul>'."\n".
                          $result."\n".
                          '</ul>';
           }
           unless ($ishome) {
               my $replicationfail;
               foreach my $item (keys(%prompttofetch)) {
                   my $fetchresult= &Apache::lonnet::reply('fetchuserfile:'.$item,$docuhome);
                   unless ($fetchresult eq 'ok') {
                       $replicationfail .= '<li>'.$item.'</li>'."\n";
                   }
               }
               if ($replicationfail) {
                   $output .= '<p class="LC_error">'.
                              &mt('Course home server failed to retrieve:').'<ul>'.
                              $replicationfail.
                              '</ul></p>';
             }              }
         }          }
     } else {      } else {
Line 10477  sub process_extracted_files { Line 12110  sub process_extracted_files {
     return $output;      return $output;
 }  }
   
   sub cleanup_empty_dirs {
       my ($path) = @_;
       if (($path ne '') && (-d $path)) {
           if (opendir(my $dirh,$path)) {
               my @dircontents = grep(!/^\./,readdir($dirh));
               my $numitems = 0;
               foreach my $item (@dircontents) {
                   if (-d "$path/$item") {
                       &cleanup_empty_dirs("$path/$item");
                       if (-e "$path/$item") {
                           $numitems ++;
                       }
                   } else {
                       $numitems ++;
                   }
               }
               if ($numitems == 0) {
                   rmdir($path);
               }
               closedir($dirh);
           }
       }
       return;
   }
   
   =pod
   
   =item * &get_folder_hierarchy()
   
   Provides hierarchy of names of folders/sub-folders containing the current
   item,
   
   Inputs: 3
        - $navmap - navmaps object
   
        - $map - url for map (either the trigger itself, or map containing
                              the resource, which is the trigger).
   
        - $showitem - 1 => show title for map itself; 0 => do not show.
   
   Outputs: 1 @pathitems - array of folder/subfolder names.
   
   =cut
   
   sub get_folder_hierarchy {
       my ($navmap,$map,$showitem) = @_;
       my @pathitems;
       if (ref($navmap)) {
           my $mapres = $navmap->getResourceByUrl($map);
           if (ref($mapres)) {
               my $pcslist = $mapres->map_hierarchy();
               if ($pcslist ne '') {
                   my @pcs = split(/,/,$pcslist);
                   foreach my $pc (@pcs) {
                       if ($pc == 1) {
                           push(@pathitems,&mt('Main Content'));
                       } else {
                           my $res = $navmap->getByMapPc($pc);
                           if (ref($res)) {
                               my $title = $res->compTitle();
                               $title =~ s/\W+/_/g;
                               if ($title ne '') {
                                   push(@pathitems,$title);
                               }
                           }
                       }
                   }
               }
               if ($showitem) {
                   if ($mapres->{ID} eq '0.0') {
                       push(@pathitems,&mt('Main Content'));
                   } else {
                       my $maptitle = $mapres->compTitle();
                       $maptitle =~ s/\W+/_/g;
                       if ($maptitle ne '') {
                           push(@pathitems,$maptitle);
                       }
                   }
               }
           }
       }
       return @pathitems;
   }
   
 =pod  =pod
   
 =item * &get_turnedin_filepath()  =item * &get_turnedin_filepath()
Line 10530  sub get_turnedin_filepath { Line 12247  sub get_turnedin_filepath {
                             my $title = $res->compTitle();                              my $title = $res->compTitle();
                             $title =~ s/\W+/_/g;                              $title =~ s/\W+/_/g;
                             if ($title ne '') {                              if ($title ne '') {
                                   if (($pc > 1) && (length($title) > 12)) {
                                       $title = substr($title,0,12);
                                   }
                                 push(@pathitems,$title);                                  push(@pathitems,$title);
                             }                              }
                         }                          }
Line 10538  sub get_turnedin_filepath { Line 12258  sub get_turnedin_filepath {
                 my $maptitle = $mapres->compTitle();                  my $maptitle = $mapres->compTitle();
                 $maptitle =~ s/\W+/_/g;                  $maptitle =~ s/\W+/_/g;
                 if ($maptitle ne '') {                  if ($maptitle ne '') {
                       if (length($maptitle) > 12) {
                           $maptitle = substr($maptitle,0,12);
                       }
                     push(@pathitems,$maptitle);                      push(@pathitems,$maptitle);
                 }                  }
                 unless ($env{'request.state'} eq 'construct') {                  unless ($env{'request.state'} eq 'construct') {
Line 10578  sub get_turnedin_filepath { Line 12301  sub get_turnedin_filepath {
                 $restitle = time;                  $restitle = time;
             }              }
         }          }
           if (length($restitle) > 12) {
               $restitle = substr($restitle,0,12);
           }
         push(@pathitems,$restitle);          push(@pathitems,$restitle);
         $path .= join('/',@pathitems);          $path .= join('/',@pathitems);
     }      }
Line 11515  sub restore_settings { Line 13241  sub restore_settings {
   
 =item * &build_recipient_list()  =item * &build_recipient_list()
   
 Build recipient lists for five types of e-mail:  Build recipient lists for following types of e-mail:
 (a) Error Reports, (b) Package Updates, (c) lonstatus warnings/errors  (a) Error Reports, (b) Package Updates, (c) lonstatus warnings/errors
 (d) Help requests, (e) Course requests needing approval,  generated by  (d) Help requests, (e) Course requests needing approval, (f) loncapa
 lonerrorhandler.pm, CHECKRPMS, loncron, lonsupportreq.pm and  module change checking, student/employee ID conflict checks, as
 loncoursequeueadmin.pm respectively.  generated by lonerrorhandler.pm, CHECKRPMS, loncron,
   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, or helpdeskmail),   mailing type (scalar: errormail, packagesmail, helpdeskmail,
   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 
   
Line 11720  sub extract_categories { Line 13450  sub extract_categories {
   
 =pod  =pod
   
 =item *&recurse_categories()  =item * &recurse_categories()
   
 Recursively used to generate breadcrumb trails for course categories.  Recursively used to generate breadcrumb trails for course categories.
   
Line 11791  sub recurse_categories { Line 13521  sub recurse_categories {
   
 =pod  =pod
   
 =item *&assign_categories_table()  =item * &assign_categories_table()
   
 Create a datatable for display of hierarchical categories in a domain,  Create a datatable for display of hierarchical categories in a domain,
 with checkboxes to allow a course to be categorized.   with checkboxes to allow a course to be categorized. 
Line 11868  sub assign_categories_table { Line 13598  sub assign_categories_table {
   
 =pod  =pod
   
 =item *&assign_category_rows()  =item * &assign_category_rows()
   
 Create a datatable row for display of nested categories in a domain,  Create a datatable row for display of nested categories in a domain,
 with checkboxes to allow a course to be categorized,called recursively.  with checkboxes to allow a course to be categorized,called recursively.
Line 11902  sub assign_category_rows { Line 13632  sub assign_category_rows {
             if (ref($cats->[$depth]{$parent}) eq 'ARRAY') {              if (ref($cats->[$depth]{$parent}) eq 'ARRAY') {
                 my $numchildren = @{$cats->[$depth]{$parent}};                  my $numchildren = @{$cats->[$depth]{$parent}};
                 my $css_class = $itemcount%2?' class="LC_odd_row"':'';                  my $css_class = $itemcount%2?' class="LC_odd_row"':'';
                 $text .= '<td><table class="LC_datatable">';                  $text .= '<td><table class="LC_data_table">';
                 for (my $j=0; $j<$numchildren; $j++) {                  for (my $j=0; $j<$numchildren; $j++) {
                     $name = $cats->[$depth]{$parent}[$j];                      $name = $cats->[$depth]{$parent}[$j];
                     $item = &escape($name).':'.&escape($parent).':'.$depth;                      $item = &escape($name).':'.&escape($parent).':'.$depth;
Line 11934  sub assign_category_rows { Line 13664  sub assign_category_rows {
     return $text;      return $text;
 }  }
   
   =pod
   
   =back
   
   =cut
   
 ############################################################  ############################################################
 ############################################################  ############################################################
   
Line 11950  sub commit_customrole { Line 13686  sub commit_customrole {
 }  }
   
 sub commit_standardrole {  sub commit_standardrole {
     my ($udom,$uname,$url,$three,$start,$end,$one,$two,$sec,$context) = @_;      my ($udom,$uname,$url,$three,$start,$end,$one,$two,$sec,$context,$credits) = @_;
     my ($output,$logmsg,$linefeed);      my ($output,$logmsg,$linefeed);
     if ($context eq 'auto') {      if ($context eq 'auto') {
         $linefeed = "\n";          $linefeed = "\n";
Line 11959  sub commit_standardrole { Line 13695  sub commit_standardrole {
     }        }  
     if ($three eq 'st') {      if ($three eq 'st') {
         my $result = &commit_studentrole(\$logmsg,$udom,$uname,$url,$three,$start,$end,          my $result = &commit_studentrole(\$logmsg,$udom,$uname,$url,$three,$start,$end,
                                          $one,$two,$sec,$context);                                           $one,$two,$sec,$context,$credits);
         if (($result =~ /^error/) || ($result eq 'not_in_class') ||           if (($result =~ /^error/) || ($result eq 'not_in_class') || 
             ($result eq 'unknown_course') || ($result eq 'refused')) {              ($result eq 'unknown_course') || ($result eq 'refused')) {
             $output = $logmsg.' '.&mt('Error: ').$result."\n";               $output = $logmsg.' '.&mt('Error: ').$result."\n"; 
Line 11990  sub commit_standardrole { Line 13726  sub commit_standardrole {
 }  }
   
 sub commit_studentrole {  sub commit_studentrole {
     my ($logmsg,$udom,$uname,$url,$three,$start,$end,$one,$two,$sec,$context) = @_;      my ($logmsg,$udom,$uname,$url,$three,$start,$end,$one,$two,$sec,$context,
           $credits) = @_;
     my ($result,$linefeed,$oldsecurl,$newsecurl);      my ($result,$linefeed,$oldsecurl,$newsecurl);
     if ($context eq 'auto') {      if ($context eq 'auto') {
         $linefeed = "\n";          $linefeed = "\n";
Line 12037  sub commit_studentrole { Line 13774  sub commit_studentrole {
             }              }
         }          }
         if (($expire_role_result eq 'ok') || ($secchange == 0)) {          if (($expire_role_result eq 'ok') || ($secchange == 0)) {
             $modify_section_result = &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$sec,$end,$start,'','',$cid,'',$context);              $modify_section_result = 
                   &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,
                                                              undef,undef,undef,$sec,
                                                              $end,$start,'','',$cid,
                                                              '',$context,$credits);
             if ($modify_section_result =~ /^ok/) {              if ($modify_section_result =~ /^ok/) {
                 if ($secchange == 1) {                  if ($secchange == 1) {
                     if ($sec eq '') {                      if ($sec eq '') {
Line 12059  sub commit_studentrole { Line 13800  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 12068  sub commit_studentrole { Line 13809  sub commit_studentrole {
             $result = $modify_section_result;              $result = $modify_section_result;
         } elsif ($secchange == 1) {          } elsif ($secchange == 1) {
             if ($oldsec eq '') {              if ($oldsec eq '') {
                 $$logmsg .= &mt('Error when attempting to expire existing role without a section for [_1] in course [_3] -error: ',$uname,$cid).' '.$expire_role_result.$linefeed;                  $$logmsg .= &mt('Error when attempting to expire existing role without a section for [_1] in course [_2] -error: ',$uname,$cid).' '.$expire_role_result.$linefeed;
             } else {              } else {
                 $$logmsg .= &mt('Error when attempting to expire existing role for [_1] in section [_2] in course [_3] -error: ',$uname,$oldsec,$cid).' '.$expire_role_result.$linefeed;                  $$logmsg .= &mt('Error when attempting to expire existing role for [_1] in section [_2] in course [_3] -error: ',$uname,$oldsec,$cid).' '.$expire_role_result.$linefeed;
             }              }
Line 12094  sub commit_studentrole { Line 13835  sub commit_studentrole {
     return $result;      return $result;
 }  }
   
   sub show_role_extent {
       my ($scope,$context,$role) = @_;
       $scope =~ s{^/}{};
       my @courseroles = &Apache::lonuserutils::roles_by_context('course',1);
       push(@courseroles,'co');
       my @authorroles = &Apache::lonuserutils::roles_by_context('author');
       if (($context eq 'course') || (grep(/^\Q$role\E/,@courseroles))) {
           $scope =~ s{/}{_};
           return '<span class="LC_cusr_emph">'.$env{'course.'.$scope.'.description'}.'</span>';
       } elsif (($context eq 'author') || (grep(/^\Q$role\E/,@authorroles))) {
           my ($audom,$auname) = split(/\//,$scope);
           return &mt('[_1] Author Space','<span class="LC_cusr_emph">'.
                      &Apache::loncommon::plainname($auname,$audom).'</span>');
       } else {
           $scope =~ s{/$}{};
           return &mt('Domain: [_1]','<span class="LC_cusr_emph">'.
                      &Apache::lonnet::domain($scope,'description').'</span>');
       }
   }
   
 ############################################################  ############################################################
 ############################################################  ############################################################
   
Line 12161  sub check_clone { Line 13922  sub check_clone {
 }  }
   
 sub construct_course {  sub construct_course {
     my ($args,$logmsg,$courseid,$crsudom,$crsunum,$udom,$uname,$context,$cnum,$category) = @_;      my ($args,$logmsg,$courseid,$crsudom,$crsunum,$udom,$uname,$context,$cnum,$category,$coderef) = @_;
     my $outcome;      my $outcome;
     my $linefeed =  '<br />'."\n";      my $linefeed =  '<br />'."\n";
     if ($context eq 'auto') {      if ($context eq 'auto') {
Line 12257  sub construct_course { Line 14018  sub construct_course {
                    'pch.users.denied',                     'pch.users.denied',
                    'plc.users.denied',                     'plc.users.denied',
                    'hidefromcat',                     'hidefromcat',
                    'categories'],                     'checkforpriv',
                      'categories',
                      'internal.uniquecode'],
                    $$crsudom,$$crsunum);                     $$crsudom,$$crsunum);
           if ($args->{'textbook'}) {
               $cenv{'internal.textbook'} = $args->{'textbook'};
           }
     }      }
   
 #  #
Line 12286  sub construct_course { Line 14052  sub construct_course {
     } else {      } else {
         $cenv{'internal.courseowner'} = $args->{'curruser'};          $cenv{'internal.courseowner'} = $args->{'curruser'};
     }      }
       if ($args->{'defaultcredits'}) {
           $cenv{'internal.defaultcredits'} = $args->{'defaultcredits'};
       }
     my @badclasses = (); # Used to accumulate sections/crosslistings that did not pass classlist access check for course owner.      my @badclasses = (); # Used to accumulate sections/crosslistings that did not pass classlist access check for course owner.
     if ($args->{'crssections'}) {      if ($args->{'crssections'}) {
         $cenv{'internal.sectionnums'} = '';          $cenv{'internal.sectionnums'} = '';
Line 12310  sub construct_course { Line 14079  sub construct_course {
 # do not hide course coordinator from staff listing,   # do not hide course coordinator from staff listing, 
 # even if privileged  # even if privileged
     $cenv{'nothideprivileged'}=$args->{'ccuname'}.':'.$args->{'ccdomain'};      $cenv{'nothideprivileged'}=$args->{'ccuname'}.':'.$args->{'ccdomain'};
   # add course coordinator's domain to domains to check for privileged users
   # if different to course domain
       if ($$crsudom ne $args->{'ccdomain'}) {
           $cenv{'checkforpriv'} = $args->{'ccdomain'};
       }
 # add crosslistings  # add crosslistings
     if ($args->{'crsxlist'}) {      if ($args->{'crsxlist'}) {
         $cenv{'internal.crosslistings'}='';          $cenv{'internal.crosslistings'}='';
Line 12434  sub construct_course { Line 14208  sub construct_course {
  }   }
     }      }
   
   #
   #  generate and store uniquecode (available to course requester), if course should have one.
   #
       if ($args->{'uniquecode'}) {
           my ($code,$error) = &make_unique_code($$crsudom,$$crsunum);
           if ($code) {
               $cenv{'internal.uniquecode'} = $code;
               my %crsinfo =
                   &Apache::lonnet::courseiddump($$crsudom,'.',1,'.','.',$$crsunum,undef,undef,'.');
               if (ref($crsinfo{$$crsudom.'_'.$$crsunum}) eq 'HASH') {
                   $crsinfo{$$crsudom.'_'.$$crsunum}{'uniquecode'} = $code;
                   my $putres = &Apache::lonnet::courseidput($$crsudom,\%crsinfo,$crsuhome,'notime');
               } 
               if (ref($coderef)) {
                   $$coderef = $code;
               }
           }
       }
   
     if ($args->{'disresdis'}) {      if ($args->{'disresdis'}) {
         $cenv{'pch.roles.denied'}='st';          $cenv{'pch.roles.denied'}='st';
     }      }
Line 12502  sub construct_course { Line 14295  sub construct_course {
     return (1,$outcome);      return (1,$outcome);
 }  }
   
   sub make_unique_code {
       my ($cdom,$cnum) = @_;
       # get lock on uniquecodes db
       my $lockhash = {
                         $cnum."\0".'uniquecodes' => $env{'user.name'}.
                                                     ':'.$env{'user.domain'},
                      };
       my $tries = 0;
       my $gotlock = &Apache::lonnet::newput_dom('uniquecodes',$lockhash,$cdom);
       my ($code,$error);
     
       while (($gotlock ne 'ok') && ($tries<3)) {
           $tries ++;
           sleep 1;
           $gotlock = &Apache::lonnet::newput_dom('uniquecodes',$lockhash,$cdom);
       }
       if ($gotlock eq 'ok') {
           my %currcodes = &Apache::lonnet::dump_dom('uniquecodes',$cdom);
           my $gotcode;
           my $attempts = 0;
           while ((!$gotcode) && ($attempts < 100)) {
               $code = &generate_code();
               if (!exists($currcodes{$code})) {
                   $gotcode = 1;
                   unless (&Apache::lonnet::newput_dom('uniquecodes',{ $code => $cnum },$cdom) eq 'ok') {
                       $error = 'nostore';
                   }
               }
               $attempts ++;
           }
           my @del_lock = ($cnum."\0".'uniquecodes');
           my $dellockoutcome = &Apache::lonnet::del_dom('uniquecodes',\@del_lock,$cdom);
       } else {
           $error = 'nolock';
       }
       return ($code,$error);
   }
   
   sub generate_code {
       my $code;
       my @letts = qw(B C D G H J K M N P Q R S T V W X Z);
       for (my $i=0; $i<6; $i++) {
           my $lettnum = int (rand 2);
           my $item = '';
           if ($lettnum) {
               $item = $letts[int( rand(18) )];
           } else {
               $item = 1+int( rand(8) );
           }
           $code .= $item;
       }
       return $code;
   }
   
 ############################################################  ############################################################
 ############################################################  ############################################################
   
Line 12529  sub group_term { Line 14376  sub group_term {
 }  }
   
 sub course_types {  sub course_types {
     my @types = ('official','unofficial','community');      my @types = ('official','unofficial','community','textbook');
     my %typename = (      my %typename = (
                          official   => 'Official course',                           official   => 'Official course',
                          unofficial => 'Unofficial course',                           unofficial => 'Unofficial course',
                          community  => 'Community',                           community  => 'Community',
                            textbook   => 'Textbook course',
                    );                     );
     return (\@types,\%typename);      return (\@types,\%typename);
 }  }
Line 12622  sub init_user_environment { Line 14470  sub init_user_environment {
   
 # See if old ID present, if so, remove  # See if old ID present, if so, remove
   
     my ($filename,$cookie,$userroles);      my ($filename,$cookie,$userroles,$firstaccenv,$timerintenv);
     my $now=time;      my $now=time;
   
     if ($public) {      if ($public) {
Line 12660  sub init_user_environment { Line 14508  sub init_user_environment {
           
 # Initialize roles  # Initialize roles
   
  $userroles=&Apache::lonnet::rolesinit($domain,$username,$authhost);   ($userroles,$firstaccenv,$timerintenv) = 
               &Apache::lonnet::rolesinit($domain,$username,$authhost);
     }      }
 # ------------------------------------ Check browser type and MathML capability  # ------------------------------------ Check browser type and MathML capability
   
     my ($httpbrowser,$clientbrowser,$clientversion,$clientmathml,      my ($httpbrowser,$clientbrowser,$clientversion,$clientmathml,
         $clientunicode,$clientos) = &decode_user_agent($r);          $clientunicode,$clientos,$clientmobile,$clientinfo) = &decode_user_agent($r);
   
 # ------------------------------------------------------------- Get environment  # ------------------------------------------------------------- Get environment
   
Line 12696  sub init_user_environment { Line 14545  sub init_user_environment {
      "browser.mathml"     => $clientmathml,       "browser.mathml"     => $clientmathml,
      "browser.unicode"    => $clientunicode,       "browser.unicode"    => $clientunicode,
      "browser.os"         => $clientos,       "browser.os"         => $clientos,
                "browser.mobile"     => $clientmobile,
                "browser.info"       => $clientinfo,
      "server.domain"      => $Apache::lonnet::perlvar{'lonDefDomain'},       "server.domain"      => $Apache::lonnet::perlvar{'lonDefDomain'},
      "request.course.fn"  => '',       "request.course.fn"  => '',
      "request.course.uri" => '',       "request.course.uri" => '',
Line 12715  sub init_user_environment { Line 14566  sub init_user_environment {
     $env{'browser.interface'}=$form->{'interface'};      $env{'browser.interface'}=$form->{'interface'};
  }   }
   
           if ($form->{'iptoken'}) {
               my $lonhost = $r->dir_config('lonHostID');
               $initial_env{"user.noloadbalance"} = $lonhost;
               $env{'user.noloadbalance'} = $lonhost;
           }
   
         my %is_adv = ( is_adv => $env{'user.adv'} );          my %is_adv = ( is_adv => $env{'user.adv'} );
         my %domdef;          my %domdef;
         unless ($domain eq 'public') {          unless ($domain eq 'public') {
             %domdef = &Apache::lonnet::get_domain_defaults($domain);              %domdef = &Apache::lonnet::get_domain_defaults($domain);
         }          }
   
         foreach my $tool ('aboutme','blog','portfolio') {          foreach my $tool ('aboutme','blog','webdav','portfolio') {
             $userenv{'availabletools.'.$tool} =               $userenv{'availabletools.'.$tool} = 
                 &Apache::lonnet::usertools_access($username,$domain,$tool,'reload',                  &Apache::lonnet::usertools_access($username,$domain,$tool,'reload',
                                                   undef,\%userenv,\%domdef,\%is_adv);                                                    undef,\%userenv,\%domdef,\%is_adv);
         }          }
   
         foreach my $crstype ('official','unofficial','community') {          foreach my $crstype ('official','unofficial','community','textbook') {
             $userenv{'canrequest.'.$crstype} =              $userenv{'canrequest.'.$crstype} =
                 &Apache::lonnet::usertools_access($username,$domain,$crstype,                  &Apache::lonnet::usertools_access($username,$domain,$crstype,
                                                   'reload','requestcourses',                                                    'reload','requestcourses',
                                                   \%userenv,\%domdef,\%is_adv);                                                    \%userenv,\%domdef,\%is_adv);
         }          }
   
           $userenv{'canrequest.author'} =
               &Apache::lonnet::usertools_access($username,$domain,'requestauthor',
                                           'reload','requestauthor',
                                           \%userenv,\%domdef,\%is_adv);
           my %reqauthor = &Apache::lonnet::get('requestauthor',['author_status','author'],
                                                $domain,$username);
           my $reqstatus = $reqauthor{'author_status'};
           if ($reqstatus eq 'approval' || $reqstatus eq 'approved') { 
               if (ref($reqauthor{'author'}) eq 'HASH') {
                   $userenv{'requestauthorqueued'} = $reqstatus.':'.
                                                     $reqauthor{'author'}{'timestamp'};
               }
           }
   
  $env{'user.environment'} = "$lonids/$cookie.id";   $env{'user.environment'} = "$lonids/$cookie.id";
   
  if (tie(my %disk_env,'GDBM_File',"$lonids/$cookie.id",   if (tie(my %disk_env,'GDBM_File',"$lonids/$cookie.id",
  &GDBM_WRCREAT(),0640)) {   &GDBM_WRCREAT(),0640)) {
     &_add_to_env(\%disk_env,\%initial_env);      &_add_to_env(\%disk_env,\%initial_env);
     &_add_to_env(\%disk_env,\%userenv,'environment.');      &_add_to_env(\%disk_env,\%userenv,'environment.');
     &_add_to_env(\%disk_env,$userroles);      &_add_to_env(\%disk_env,$userroles);
               if (ref($firstaccenv) eq 'HASH') {
                   &_add_to_env(\%disk_env,$firstaccenv);
               }
               if (ref($timerintenv) eq 'HASH') {
                   &_add_to_env(\%disk_env,$timerintenv);
               }
     if (ref($args->{'extra_env'})) {      if (ref($args->{'extra_env'})) {
  &_add_to_env(\%disk_env,$args->{'extra_env'});   &_add_to_env(\%disk_env,$args->{'extra_env'});
     }      }
Line 12776  sub get_symb { Line 14653  sub get_symb {
     my $symb=($env{'form.symb'} ne '' ? $env{'form.symb'} : (&Apache::lonnet::symbread($url)));      my $symb=($env{'form.symb'} ne '' ? $env{'form.symb'} : (&Apache::lonnet::symbread($url)));
     if ($symb eq '') {      if ($symb eq '') {
         if (!$silent) {          if (!$silent) {
             $request->print("Unable to handle ambiguous references:$url:.");              if (ref($request)) { 
                   $request->print("Unable to handle ambiguous references:$url:.");
               }
             return ();              return ();
         }          }
     }      }
Line 12810  sub clean_symb { Line 14689  sub clean_symb {
     return ($symb,$enc);      return ($symb,$enc);
 }  }
   
   ############################################################
   ############################################################
   
   =pod
   
   =head1 Routines for building display used to search for courses
   
   
   =over 4
   
   =item * &build_filters()
   
   Create markup for a table used to set filters to use when selecting
   courses in a domain.  Used by lonpickcourse.pm, lonmodifycourse.pm
   and quotacheck.pl
   
   
   Inputs:
   
   filterlist - anonymous array of fields to include as potential filters 
   
   crstype - course type
   
   roleelement - fifth arg in selectcourse_link() populates fifth arg in javascript: opencrsbrowser() function, used
                 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
   
   filter - anonymous hash of criteria and their values
   
   action - form action
   
   numfiltersref - ref to scalar (count of number of elements in institutional codes -- e.g., 4 for year, semester, department, and number)
   
   caller - caller context (e.g., set to 'modifycourse' when routine is called from lonmodifycourse.pm)
   
   cloneruname - username 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) 
   
   codetitlesref - reference to array of titles of components in institutional codes (official courses)
   
   codedom - domain
   
   formname - value of form element named "form". 
   
   fixeddom - domain, if fixed.
   
   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 
   
   cnumelement - name of form element in form on opener page which will receive courseID  of selected course
   
   cdomelement - name of form element in form on opener page which will receive domain of selected course
   
   setroles - includes access constraint identifier when setting a roles-based condition for acces to a portfolio file
   
   clonetext - hidden form elements containing list of courses cloneable by intended course owner when DC creates a course
   
   clonewarning - warning message about missing information for intended course owner when DC creates a course
   
   
   Returns: $output - HTML for display of search criteria, and hidden form elements.
   
   
   Side Effects: None
   
   =cut
   
   # ---------------------------------------------- search for courses based on last activity etc.
   
   sub build_filters {
       my ($filterlist,$crstype,$roleelement,$multelement,$filter,$action,
           $numtitlesref,$caller,$cloneruname,$clonerudom,$typeelement,
           $codetitlesref,$codedom,$formname,$fixeddom,$prevphase,
           $cnameelement,$cnumelement,$cdomelement,$setroles,
           $clonetext,$clonewarning) = @_;
       my ($list,$jscript);
       my $onchange = 'javascript:updateFilters(this)';
       my ($domainselectform,$sincefilterform,$createdfilterform,
           $ownerdomselectform,$persondomselectform,$instcodeform,
           $typeselectform,$instcodetitle);
       if ($formname eq '') {
           $formname = $caller;
       }
       foreach my $item (@{$filterlist}) {
           unless (($item eq 'descriptfilter') || ($item eq 'instcodefilter') ||
                   ($item eq 'sincefilter') || ($item eq 'createdfilter')) {
               if ($item eq 'domainfilter') {
                   $filter->{$item} = &LONCAPA::clean_domain($filter->{$item});
               } elsif ($item eq 'coursefilter') {
                   $filter->{$item} = &LONCAPA::clean_courseid($filter->{$item});
               } elsif ($item eq 'ownerfilter') {
                   $filter->{$item} = &LONCAPA::clean_username($filter->{$item});
               } elsif ($item eq 'ownerdomfilter') {
                   $filter->{'ownerdomfilter'} =
                       &LONCAPA::clean_domain($filter->{$item});
                   $ownerdomselectform = &select_dom_form($filter->{'ownerdomfilter'},
                                                          'ownerdomfilter',1);
               } elsif ($item eq 'personfilter') {
                   $filter->{$item} = &LONCAPA::clean_username($filter->{$item});
               } elsif ($item eq 'persondomfilter') {
                   $persondomselectform = &select_dom_form($filter->{'persondomfilter'},
                                                           'persondomfilter',1);
               } else {
                   $filter->{$item} =~ s/\W//g;
               }
               if (!$filter->{$item}) {
                   $filter->{$item} = '';
               }
           }
           if ($item eq 'domainfilter') {
               my $allow_blank = 1;
               if ($formname eq 'portform') {
                   $allow_blank=0;
               } elsif ($formname eq 'studentform') {
                   $allow_blank=0;
               }
               if ($fixeddom) {
                   $domainselectform = '<input type="hidden" name="domainfilter"'.
                                       ' value="'.$codedom.'" />'.
                                       &Apache::lonnet::domain($codedom,'description');
               } else {
                   $domainselectform = &select_dom_form($filter->{$item},
                                                        'domainfilter',
                                                         $allow_blank,'',$onchange);
               }
           } else {
               $list->{$item} = &HTML::Entities::encode($filter->{$item},'<>&"');
           }
       }
   
       # last course activity filter and selection
       $sincefilterform = &timebased_select_form('sincefilter',$filter);
   
       # course created filter and selection
       if (exists($filter->{'createdfilter'})) {
           $createdfilterform = &timebased_select_form('createdfilter',$filter);
       }
   
       my %lt = &Apache::lonlocal::texthash(
                   'cac' => "$crstype Activity",
                   'ccr' => "$crstype Created",
                   'cde' => "$crstype Title",
                   'cdo' => "$crstype Domain",
                   'ins' => 'Institutional Code',
                   'inc' => 'Institutional Categorization',
                   'cow' => "$crstype Owner/Co-owner",
                   'cop' => "$crstype Personnel Includes",
                   'cog' => 'Type',
                );
   
       if (($formname eq 'ccrs') || ($formname eq 'requestcrs')) {
           my $typeval = 'Course';
           if ($crstype eq 'Community') {
               $typeval = 'Community';
           }
           $typeselectform = '<input type="hidden" name="type" value="'.$typeval.'" />';
       } else {
           $typeselectform =  '<select name="type" size="1"';
           if ($onchange) {
               $typeselectform .= ' onchange="'.$onchange.'"';
           }
           $typeselectform .= '>'."\n";
           foreach my $posstype ('Course','Community') {
               $typeselectform.='<option value="'.$posstype.'"'.
                   ($posstype eq $crstype ? ' selected="selected" ' : ''). ">".&mt($posstype)."</option>\n";
           }
           $typeselectform.="</select>";
       }
   
       my ($cloneableonlyform,$cloneabletitle);
       if (exists($filter->{'cloneableonly'})) {
           my $cloneableon = '';
           my $cloneableoff = ' checked="checked"';
           if ($filter->{'cloneableonly'}) {
               $cloneableon = $cloneableoff;
               $cloneableoff = '';
           }
           $cloneableonlyform = '<span class="LC_nobreak"><label><input type="radio" name="cloneableonly" value="1" '.$cloneableon.'/>&nbsp;'.&mt('Required').'</label>'.('&nbsp;'x3).'<label><input type="radio" name="cloneableonly" value="" '.$cloneableoff.' />&nbsp;'.&mt('No restriction').'</label></span>';
           if ($formname eq 'ccrs') {
               $cloneabletitle = &mt('Cloneable for').' '.$cloneruname.':'.$clonerudom;
           } else {
               $cloneabletitle = &mt('Cloneable by you');
           }
       }
       my $officialjs;
       if ($crstype eq 'Course') {
           if (exists($filter->{'instcodefilter'})) {
   #            if (($fixeddom) || ($formname eq 'requestcrs') ||
   #                ($formname eq 'modifycourse') || ($formname eq 'filterpicker')) {
               if ($codedom) { 
                   $officialjs = 1;
                   ($instcodeform,$jscript,$$numtitlesref) =
                       &Apache::courseclassifier::instcode_selectors($codedom,'filterpicker',
                                                                     $officialjs,$codetitlesref);
                   if ($jscript) {
                       $jscript = '<script type="text/javascript">'."\n".
                                  '// <![CDATA['."\n".
                                  $jscript."\n".
                                  '// ]]>'."\n".
                                  '</script>'."\n";
                   }
               }
               if ($instcodeform eq '') {
                   $instcodeform =
                       '<input type="text" name="instcodefilter" size="10" value="'.
                       $list->{'instcodefilter'}.'" />';
                   $instcodetitle = $lt{'ins'};
               } else {
                   $instcodetitle = $lt{'inc'};
               }
               if ($fixeddom) {
                   $instcodetitle .= '<br />('.$codedom.')';
               }
           }
       }
       my $output = qq|
   <form method="post" name="filterpicker" action="$action">
   <input type="hidden" name="form" value="$formname" />
   |;
       if ($formname eq 'modifycourse') {
           $output .= '<input type="hidden" name="phase" value="courselist" />'."\n".
                      '<input type="hidden" name="prevphase" value="'.
                      $prevphase.'" />'."\n";
       } elsif ($formname ne 'quotacheck') {
           my $name_input;
           if ($cnameelement ne '') {
               $name_input = '<input type="hidden" name="cnameelement" value="'.
                             $cnameelement.'" />';
           }
           $output .= qq|
   <input type="hidden" name="cnumelement" value="$cnumelement" />
   <input type="hidden" name="cdomelement" value="$cdomelement" />
   $name_input
   $roleelement
   $multelement
   $typeelement
   |;
           if ($formname eq 'portform') {
               $output .= '<input type="hidden" name="setroles" value="'.$setroles.'" />'."\n";
           }
       }
       if ($fixeddom) {
           $output .= '<input type="hidden" name="fixeddom" value="'.$fixeddom.'" />'."\n";
       }
       $output .= "<br />\n".&Apache::lonhtmlcommon::start_pick_box();
       if ($sincefilterform) {
           $output .= &Apache::lonhtmlcommon::row_title($lt{'cac'})
                     .$sincefilterform
                     .&Apache::lonhtmlcommon::row_closure();
       }
       if ($createdfilterform) {
           $output .= &Apache::lonhtmlcommon::row_title($lt{'ccr'})
                     .$createdfilterform
                     .&Apache::lonhtmlcommon::row_closure();
       }
       if ($domainselectform) {
           $output .= &Apache::lonhtmlcommon::row_title($lt{'cdo'})
                     .$domainselectform
                     .&Apache::lonhtmlcommon::row_closure();
       }
       if ($typeselectform) {
           if (($formname eq 'ccrs') || ($formname eq 'requestcrs')) {
               $output .= $typeselectform;
           } else {
               $output .= &Apache::lonhtmlcommon::row_title($lt{'cog'})
                         .$typeselectform
                         .&Apache::lonhtmlcommon::row_closure();
           }
       }
       if ($instcodeform) {
           $output .= &Apache::lonhtmlcommon::row_title($instcodetitle)
                     .$instcodeform
                     .&Apache::lonhtmlcommon::row_closure();
       }
       if (exists($filter->{'ownerfilter'})) {
           $output .= &Apache::lonhtmlcommon::row_title($lt{'cow'}).
                      '<table><tr><td>'.&mt('Username').'<br />'.
                      '<input type="text" name="ownerfilter" size="20" value="'.
                      $list->{'ownerfilter'}.'" /></td><td>'.&mt('Domain').'<br />'.
                      $ownerdomselectform.'</td></tr></table>'.
                      &Apache::lonhtmlcommon::row_closure();
       }
       if (exists($filter->{'personfilter'})) {
           $output .= &Apache::lonhtmlcommon::row_title($lt{'cop'}).
                      '<table><tr><td>'.&mt('Username').'<br />'.
                      '<input type="text" name="personfilter" size="20" value="'.
                      $list->{'personfilter'}.'" /></td><td>'.&mt('Domain').'<br />'.
                      $persondomselectform.'</td></tr></table>'.
                      &Apache::lonhtmlcommon::row_closure();
       }
       if (exists($filter->{'coursefilter'})) {
           $output .= &Apache::lonhtmlcommon::row_title(&mt('LON-CAPA course ID'))
                     .'<input type="text" name="coursefilter" size="25" value="'
                     .$list->{'coursefilter'}.'" />'
                     .&Apache::lonhtmlcommon::row_closure();
       }
       if ($cloneableonlyform) {
           $output .= &Apache::lonhtmlcommon::row_title($cloneabletitle).
                      $cloneableonlyform.&Apache::lonhtmlcommon::row_closure();
       }
       if (exists($filter->{'descriptfilter'})) {
           $output .= &Apache::lonhtmlcommon::row_title($lt{'cde'})
                     .'<input type="text" name="descriptfilter" size="40" value="'
                     .$list->{'descriptfilter'}.'" />'
                     .&Apache::lonhtmlcommon::row_closure(1);
       }
       $output .= &Apache::lonhtmlcommon::end_pick_box().'<p>'.$clonetext."\n".
                  '<input type="hidden" name="updater" value="" />'."\n".
                  '<input type="submit" name="gosearch" value="'.
                  &mt('Search').'" /></p>'."\n".'</form>'."\n".'<hr />'."\n";
       return $jscript.$clonewarning.$output;
   }
   
   =pod 
   
   =item * &timebased_select_form()
   
   Create markup for a dropdown list used to select a time-based
   filter e.g., Course Activity, Course Created, when searching for courses
   or communities
   
   Inputs:
   
   item - name of form element (sincefilter or createdfilter)
   
   filter - anonymous hash of criteria and their values
   
   Returns: HTML for a select box contained a blank, then six time selections,
            with value set in incoming form variables currently selected. 
   
   Side Effects: None
   
   =cut
   
   sub timebased_select_form {
       my ($item,$filter) = @_;
       if (ref($filter) eq 'HASH') {
           $filter->{$item} =~ s/[^\d-]//g;
           if (!$filter->{$item}) { $filter->{$item}=-1; }
           return &select_form(
                               $filter->{$item},
                               $item,
                               {      '-1' => '',
                                   '86400' => &mt('today'),
                                  '604800' => &mt('last week'),
                                 '2592000' => &mt('last month'),
                                 '7776000' => &mt('last three months'),
                                '15552000' => &mt('last six months'),
                                '31104000' => &mt('last year'),
                       'select_form_order' =>
                              ['-1','86400','604800','2592000','7776000',
                               '15552000','31104000']});
       }
   }
   
   =pod
   
   =item * &js_changer()
   
   Create script tag containing Javascript used to submit course search form
   when course type or domain is changed, and also to hide 'Searching ...' on
   page load completion for page showing search result.
   
   Inputs: None
   
   Returns: markup containing updateFilters() and hideSearching() javascript functions. 
   
   Side Effects: None
   
   =cut
   
   sub js_changer {
       return <<ENDJS;
   <script type="text/javascript">
   // <![CDATA[
   function updateFilters(caller) {
       if (typeof(caller) != "undefined") {
           document.filterpicker.updater.value = caller.name;
       }
       document.filterpicker.submit();
   }
   
   function hideSearching() {
       if (document.getElementById('searching')) {
           document.getElementById('searching').style.display = 'none';
       }
       return;
   }
   
   // ]]>
   </script>
   
   ENDJS
   }
   
   =pod
   
   =item * &search_courses()
   
   Process selected filters form course search form and pass to lonnet::courseiddump
   to retrieve a hash for which keys are courseIDs which match the selected filters.
   
   Inputs:
   
   dom - domain being searched 
   
   type - course type ('Course' or 'Community' or '.' if any).
   
   filter - anonymous hash of criteria and their values
   
   numtitles - for institutional codes - number of categories
   
   cloneruname - optional username 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, 
               (used when DC is using course creation form)
   
   codetitles - reference to array of titles of components in institutional codes (official courses).
   
   
   Returns: %courses - hash of courses satisfying search criteria, keys = course IDs, values are corresponding colon-separated escaped description, institutional code, owner and type.
   
   
   Side Effects: None
   
   =cut
   
   
   sub search_courses {
       my ($dom,$type,$filter,$numtitles,$cloneruname,$clonerudom,$domcloner,$codetitles) = @_;
       my (%courses,%showcourses,$cloner);
       if (($filter->{'ownerfilter'} ne '') ||
           ($filter->{'ownerdomfilter'} ne '')) {
           $filter->{'combownerfilter'} = $filter->{'ownerfilter'}.':'.
                                          $filter->{'ownerdomfilter'};
       }
       foreach my $item ('descriptfilter','coursefilter','combownerfilter') {
           if (!$filter->{$item}) {
               $filter->{$item}='.';
           }
       }
       my $now = time;
       my $timefilter =
          ($filter->{'sincefilter'}==-1?1:$now-$filter->{'sincefilter'});
       my ($createdbefore,$createdafter);
       if (($filter->{'createdfilter'} ne '') && ($filter->{'createdfilter'} !=-1)) {
           $createdbefore = $now;
           $createdafter = $now-$filter->{'createdfilter'};
       }
       my ($instcodefilter,$regexpok);
       if ($numtitles) {
           if ($env{'form.official'} eq 'on') {
               $instcodefilter =
                   &Apache::courseclassifier::instcode_search_str($dom,$numtitles,$codetitles);
               $regexpok = 1;
           } elsif ($env{'form.official'} eq 'off') {
               $instcodefilter = &Apache::courseclassifier::instcode_search_str($dom,$numtitles,$codetitles);
               unless ($instcodefilter eq '') {
                   $regexpok = -1;
               }
           }
       } else {
           $instcodefilter = $filter->{'instcodefilter'};
       }
       if ($instcodefilter eq '') { $instcodefilter = '.'; }
       if ($type eq '') { $type = '.'; }
   
       if (($clonerudom ne '') && ($cloneruname ne '')) {
           $cloner = $cloneruname.':'.$clonerudom;
       }
       %courses = &Apache::lonnet::courseiddump($dom,
                                                $filter->{'descriptfilter'},
                                                $timefilter,
                                                $instcodefilter,
                                                $filter->{'combownerfilter'},
                                                $filter->{'coursefilter'},
                                                undef,undef,$type,$regexpok,undef,undef,
                                                undef,undef,$cloner,$env{'form.cc_clone'},
                                                $filter->{'cloneableonly'},
                                                $createdbefore,$createdafter,undef,
                                                $domcloner);
       if (($filter->{'personfilter'} ne '') && ($filter->{'persondomfilter'} ne '')) {
           my $ccrole;
           if ($type eq 'Community') {
               $ccrole = 'co';
           } else {
               $ccrole = 'cc';
           }
           my %rolehash = &Apache::lonnet::get_my_roles($filter->{'personfilter'},
                                                        $filter->{'persondomfilter'},
                                                        'userroles',undef,
                                                        [$ccrole,'in','ad','ep','ta','cr'],
                                                        $dom);
           foreach my $role (keys(%rolehash)) {
               my ($cnum,$cdom,$courserole) = split(':',$role);
               my $cid = $cdom.'_'.$cnum;
               if (exists($courses{$cid})) {
                   if (ref($courses{$cid}) eq 'HASH') {
                       if (ref($courses{$cid}{roles}) eq 'ARRAY') {
                           if (!grep(/^\Q$courserole\E$/,@{$courses{$cid}{roles}})) {
                               push (@{$courses{$cid}{roles}},$courserole);
                           }
                       } else {
                           $courses{$cid}{roles} = [$courserole];
                       }
                       $showcourses{$cid} = $courses{$cid};
                   }
               }
           }
           %courses = %showcourses;
       }
       return %courses;
   }
   
   
   =pod
   
   =back
   
   =cut
   
   
 sub build_release_hashes {  sub build_release_hashes {
     my ($checkparms,$checkresponsetypes,$checkcrstypes,$anonsurvey,$randomizetry) = @_;      my ($checkparms,$checkresponsetypes,$checkcrstypes,$anonsurvey,$randomizetry) = @_;
     return unless((ref($checkparms) eq 'HASH') && (ref($checkresponsetypes) eq 'HASH') &&      return unless((ref($checkparms) eq 'HASH') && (ref($checkresponsetypes) eq 'HASH') &&
Line 12840  sub build_release_hashes { Line 15248  sub build_release_hashes {
     return;      return;
 }  }
   
 =pod  sub update_content_constraints {
       my ($cdom,$cnum,$chome,$cid) = @_;
       my %curr_reqd_hash = &Apache::lonnet::userenvironment($cdom,$cnum,'internal.releaserequired');
       my ($reqdmajor,$reqdminor) = split(/\./,$curr_reqd_hash{'internal.releaserequired'});
       my %checkresponsetypes;
       foreach my $key (keys(%Apache::lonnet::needsrelease)) {
           my ($item,$name,$value) = split(/:/,$key);
           if ($item eq 'resourcetag') {
               if ($name eq 'responsetype') {
                   $checkresponsetypes{$value} = $Apache::lonnet::needsrelease{$key}
               }
           }
       }
       my $navmap = Apache::lonnavmaps::navmap->new();
       if (defined($navmap)) {
           my %allresponses;
           foreach my $res ($navmap->retrieveResources(undef,sub { $_[0]->is_problem() },1,0)) {
               my %responses = $res->responseTypes();
               foreach my $key (keys(%responses)) {
                   next unless(exists($checkresponsetypes{$key}));
                   $allresponses{$key} += $responses{$key};
               }
           }
           foreach my $key (keys(%allresponses)) {
               my ($major,$minor) = split(/\./,$checkresponsetypes{$key});
               if (($major > $reqdmajor) || ($major == $reqdmajor && $minor > $reqdminor)) {
                   ($reqdmajor,$reqdminor) = ($major,$minor);
               }
           }
           undef($navmap);
       }
       unless (($reqdmajor eq '') && ($reqdminor eq '')) {
           &Apache::lonnet::update_released_required($reqdmajor.'.'.$reqdminor,$cdom,$cnum,$chome,$cid);
       }
       return;
   }
   
 =back  sub allmaps_incourse {
       my ($cdom,$cnum,$chome,$cid) = @_;
       if ($cdom eq '' || $cnum eq '' || $chome eq '' || $cid eq '') {
           $cid = $env{'request.course.id'};
           $cdom = $env{'course.'.$cid.'.domain'};
           $cnum = $env{'course.'.$cid.'.num'};
           $chome = $env{'course.'.$cid.'.home'};
       }
       my %allmaps = ();
       my $lastchange =
           &Apache::lonnet::get_coursechange($cdom,$cnum);
       if ($lastchange > $env{'request.course.tied'}) {
           my ($furl,$ferr) = &Apache::lonuserstate::readmap("$cdom/$cnum");
           unless ($ferr) {
               &update_content_constraints($cdom,$cnum,$chome,$cid);
           }
       }
       my $navmap = Apache::lonnavmaps::navmap->new();
       if (defined($navmap)) {
           foreach my $res ($navmap->retrieveResources(undef,sub { $_[0]->is_map() },1,0,1)) {
               $allmaps{$res->src()} = 1;
           }
       }
       return \%allmaps;
   }
   
   sub parse_supplemental_title {
       my ($title) = @_;
   
       my ($foldertitle,$renametitle);
       if ($title =~ /&amp;&amp;&amp;/) {
           $title = &HTML::Entites::decode($title);
       }
       if ($title =~ m/^(\d+)___&&&___($match_username)___&&&___($match_domain)___&&&___(.*)$/) {
           $renametitle=$4;
           my ($time,$uname,$udom) = ($1,$2,$3);
           $foldertitle=&Apache::lontexconvert::msgtexconverted($4);
           my $name =  &plainname($uname,$udom);
           $name = &HTML::Entities::encode($name,'"<>&\'');
           $renametitle = &HTML::Entities::encode($renametitle,'"<>&\'');
           $title='<i>'.&Apache::lonlocal::locallocaltime($time).'</i> '.
               $name.': <br />'.$foldertitle;
       }
       if (wantarray) {
           return ($title,$foldertitle,$renametitle);
       }
       return $title;
   }
   
 =cut  sub recurse_supplemental {
       my ($cnum,$cdom,$suppmap,$numfiles,$errors) = @_;
       if ($suppmap) {
           my ($errtext,$fatal) = &LONCAPA::map::mapread('/uploaded/'.$cdom.'/'.$cnum.'/'.$suppmap);
           if ($fatal) {
               $errors ++;
           } else {
               if ($#LONCAPA::map::resources > 0) {
                   foreach my $res (@LONCAPA::map::resources) {
                       my ($title,$src,$ext,$type,$status)=split(/\:/,$res);
                       if (($src ne '') && ($status eq 'res')) {
                           if ($src =~ m{^\Q/uploaded/$cdom/$cnum/\E(supplemental_\d+\.sequence)$}) {
                               ($numfiles,$errors) = &recurse_supplemental($cnum,$cdom,$1,$numfiles,$errors);
                           } else {
                               $numfiles ++;
                           }
                       }
                   }
               }
           }
       }
       return ($numfiles,$errors);
   }
   
   sub symb_to_docspath {
       my ($symb) = @_;
       return unless ($symb);
       my ($mapurl,$id,$resurl) = &Apache::lonnet::decode_symb($symb);
       if ($resurl=~/\.(sequence|page)$/) {
           $mapurl=$resurl;
       } elsif ($resurl eq 'adm/navmaps') {
           $mapurl=$env{'course.'.$env{'request.course.id'}.'.url'};
       }
       my $mapresobj;
       my $navmap = Apache::lonnavmaps::navmap->new();
       if (ref($navmap)) {
           $mapresobj = $navmap->getResourceByUrl($mapurl);
       }
       $mapurl=~s{^.*/([^/]+)\.(\w+)$}{$1};
       my $type=$2;
       my $path;
       if (ref($mapresobj)) {
           my $pcslist = $mapresobj->map_hierarchy();
           if ($pcslist ne '') {
               foreach my $pc (split(/,/,$pcslist)) {
                   next if ($pc <= 1);
                   my $res = $navmap->getByMapPc($pc);
                   if (ref($res)) {
                       my $thisurl = $res->src();
                       $thisurl=~s{^.*/([^/]+)\.\w+$}{$1};
                       my $thistitle = $res->title();
                       $path .= '&'.
                                &Apache::lonhtmlcommon::entity_encode($thisurl).'&'.
                                &escape($thistitle).
                                ':'.$res->randompick().
                                ':'.$res->randomout().
                                ':'.$res->encrypted().
                                ':'.$res->randomorder().
                                ':'.$res->is_page();
                   }
               }
           }
           $path =~ s/^\&//;
           my $maptitle = $mapresobj->title();
           if ($mapurl eq 'default') {
               $maptitle = 'Main Content';
           }
           $path .= (($path ne '')? '&' : '').
                    &Apache::lonhtmlcommon::entity_encode($mapurl).'&'.
                    &escape($maptitle).
                    ':'.$mapresobj->randompick().
                    ':'.$mapresobj->randomout().
                    ':'.$mapresobj->encrypted().
                    ':'.$mapresobj->randomorder().
                    ':'.$mapresobj->is_page();
       } else {
           my $maptitle = &Apache::lonnet::gettitle($mapurl);
           my $ispage = (($type eq 'page')? 1 : '');
           if ($mapurl eq 'default') {
               $maptitle = 'Main Content';
           }
           $path = &Apache::lonhtmlcommon::entity_encode($mapurl).'&'.
                   &escape($maptitle).':::::'.$ispage;
       }
       unless ($mapurl eq 'default') {
           $path = 'default&'.
                   &escape('Main Content').
                   ':::::&'.$path;
       }
       return $path;
   }
   
   sub captcha_display {
       my ($context,$lonhost) = @_;
       my ($output,$error);
       my ($captcha,$pubkey,$privkey) = &get_captcha_config($context,$lonhost);
       if ($captcha eq 'original') {
           $output = &create_captcha();
           unless ($output) {
               $error = 'captcha';
           }
       } elsif ($captcha eq 'recaptcha') {
           $output = &create_recaptcha($pubkey);
           unless ($output) {
               $error = 'recaptcha';
           }
       }
       return ($output,$error,$captcha);
   }
   
   sub captcha_response {
       my ($context,$lonhost) = @_;
       my ($captcha_chk,$captcha_error);
       my ($captcha,$pubkey,$privkey) = &get_captcha_config($context,$lonhost);
       if ($captcha eq 'original') {
           ($captcha_chk,$captcha_error) = &check_captcha();
       } elsif ($captcha eq 'recaptcha') {
           $captcha_chk = &check_recaptcha($privkey);
       } else {
           $captcha_chk = 1;
       }
       return ($captcha_chk,$captcha_error);
   }
   
   sub get_captcha_config {
       my ($context,$lonhost) = @_;
       my ($captcha,$pubkey,$privkey,$hashtocheck);
       my $hostname = &Apache::lonnet::hostname($lonhost);
       my $serverhomeID = &Apache::lonnet::get_server_homeID($hostname);
       my $serverhomedom = &Apache::lonnet::host_domain($serverhomeID);
       if ($context eq 'usercreation') {
           my %domconfig = &Apache::lonnet::get_dom('configuration',[$context],$serverhomedom);
           if (ref($domconfig{$context}) eq 'HASH') {
               $hashtocheck = $domconfig{$context}{'cancreate'};
               if (ref($hashtocheck) eq 'HASH') {
                   if ($hashtocheck->{'captcha'} eq 'recaptcha') {
                       if (ref($hashtocheck->{'recaptchakeys'}) eq 'HASH') {
                           $pubkey = $hashtocheck->{'recaptchakeys'}{'public'};
                           $privkey = $hashtocheck->{'recaptchakeys'}{'private'};
                       }
                       if ($privkey && $pubkey) {
                           $captcha = 'recaptcha';
                       } else {
                           $captcha = 'original';
                       }
                   } elsif ($hashtocheck->{'captcha'} ne 'notused') {
                       $captcha = 'original';
                   }
               }
           } else {
               $captcha = 'captcha';
           }
       } elsif ($context eq 'login') {
           my %domconfhash = &Apache::loncommon::get_domainconf($serverhomedom);
           if ($domconfhash{$serverhomedom.'.login.captcha'} eq 'recaptcha') {
               $pubkey = $domconfhash{$serverhomedom.'.login.recaptchakeys_public'};
               $privkey = $domconfhash{$serverhomedom.'.login.recaptchakeys_private'};
               if ($privkey && $pubkey) {
                   $captcha = 'recaptcha';
               } else {
                   $captcha = 'original';
               }
           } elsif ($domconfhash{$serverhomedom.'.login.captcha'} eq 'original') {
               $captcha = 'original';
           }
       }
       return ($captcha,$pubkey,$privkey);
   }
   
   sub create_captcha {
       my %captcha_params = &captcha_settings();
       my ($output,$maxtries,$tries) = ('',10,0);
       while ($tries < $maxtries) {
           $tries ++;
           my $captcha = Authen::Captcha->new (
                                              output_folder => $captcha_params{'output_dir'},
                                              data_folder   => $captcha_params{'db_dir'},
                                             );
           my $md5sum = $captcha->generate_code($captcha_params{'numchars'});
   
           if (-e $Apache::lonnet::perlvar{'lonCaptchaDir'}.'/'.$md5sum.'.png') {
               $output = '<input type="hidden" name="crypt" value="'.$md5sum.'" />'."\n".
                         &mt('Type in the letters/numbers shown below').'&nbsp;'.
                         '<input type="text" size="5" name="code" value="" autocomplete="off" />'.
                         '<br />'.
                         '<img src="'.$captcha_params{'www_output_dir'}.'/'.$md5sum.'.png" alt="captcha" />';
               last;
           }
       }
       return $output;
   }
   
   sub captcha_settings {
       my %captcha_params = (
                              output_dir     => $Apache::lonnet::perlvar{'lonCaptchaDir'},
                              www_output_dir => "/captchaspool",
                              db_dir         => $Apache::lonnet::perlvar{'lonCaptchaDb'},
                              numchars       => '5',
                            );
       return %captcha_params;
   }
   
   sub check_captcha {
       my ($captcha_chk,$captcha_error);
       my $code = $env{'form.code'};
       my $md5sum = $env{'form.crypt'};
       my %captcha_params = &captcha_settings();
       my $captcha = Authen::Captcha->new(
                         output_folder => $captcha_params{'output_dir'},
                         data_folder   => $captcha_params{'db_dir'},
                     );
       $captcha_chk = $captcha->check_code($code,$md5sum);
       my %captcha_hash = (
                           0       => 'Code not checked (file error)',
                          -1      => 'Failed: code expired',
                          -2      => 'Failed: invalid code (not in database)',
                          -3      => 'Failed: invalid code (code does not match crypt)',
       );
       if ($captcha_chk != 1) {
           $captcha_error = $captcha_hash{$captcha_chk}
       }
       return ($captcha_chk,$captcha_error);
   }
   
   sub create_recaptcha {
       my ($pubkey) = @_;
       my $use_ssl;
       if ($ENV{'SERVER_PORT'} == 443) {
           $use_ssl = 1;
       }
       my $captcha = Captcha::reCAPTCHA->new;
       return $captcha->get_options_setter({theme => 'white'})."\n".
              $captcha->get_html($pubkey,undef,$use_ssl).
              &mt('If either word is hard to read, [_1] will replace them.',
                  '<img src="/res/adm/pages/refresh.gif" alt="reCAPTCHA refresh" />').
              '<br /><br />';
   }
   
   sub check_recaptcha {
       my ($privkey) = @_;
       my $captcha_chk;
       my $captcha = Captcha::reCAPTCHA->new;
       my $captcha_result =
           $captcha->check_answer(
                                   $privkey,
                                   $ENV{'REMOTE_ADDR'},
                                   $env{'form.recaptcha_challenge_field'},
                                   $env{'form.recaptcha_response_field'},
                                 );
       if ($captcha_result->{is_valid}) {
           $captcha_chk = 1;
       }
       return $captcha_chk;
   }
   
   sub emailusername_info {
       my @fields = ('firstname','lastname','institution','web','location','officialemail');
       my %titles = &Apache::lonlocal::texthash (
                        lastname      => 'Last Name',
                        firstname     => 'First Name',
                        institution   => 'School/college/university',
                        location      => "School's city, state/province, country",
                        web           => "School's web address",
                        officialemail => 'E-mail address at institution (if different)',
                    );
       return (\@fields,\%titles);
   }
   
   sub cleanup_html {
       my ($incoming) = @_;
       my $outgoing;
       if ($incoming ne '') {
           $outgoing = $incoming;
           $outgoing =~ s/;/&#059;/g;
           $outgoing =~ s/\#/&#035;/g;
           $outgoing =~ s/\&/&#038;/g;
           $outgoing =~ s/</&#060;/g;
           $outgoing =~ s/>/&#062;/g;
           $outgoing =~ s/\(/&#040/g;
           $outgoing =~ s/\)/&#041;/g;
           $outgoing =~ s/"/&#034;/g;
           $outgoing =~ s/'/&#039;/g;
           $outgoing =~ s/\$/&#036;/g;
           $outgoing =~ s{/}{&#047;}g;
           $outgoing =~ s/=/&#061;/g;
           $outgoing =~ s/\\/&#092;/g
       }
       return $outgoing;
   }
   
   # Use:
   #   my $answer=reply("encrypt:passwd:$udom:$uname:$upass",$tryserver);
   #
   ##################################################
   #          password associated functions         #
   ##################################################
   sub des_keys {
       # Make a new key for DES encryption.
       # Each key has two parts which are returned separately.
       # Please note:  Each key must be passed through the &hex function
       # before it is output to the web browser.  The hex versions cannot
       # be used to decrypt.
       my @hexstr=('0','1','2','3','4','5','6','7',
                   '8','9','a','b','c','d','e','f');
       my $lkey='';
       for (0..7) {
           $lkey.=$hexstr[rand(15)];
       }
       my $ukey='';
       for (0..7) {
           $ukey.=$hexstr[rand(15)];
       }
       return ($lkey,$ukey);
   }
   
   sub des_decrypt {
       my ($key,$cyphertext) = @_;
       my $keybin=pack("H16",$key);
       my $cypher;
       if ($Crypt::DES::VERSION>=2.03) {
           $cypher=new Crypt::DES $keybin;
       } else {
           $cypher=new DES $keybin;
       }
       my $plaintext=
           $cypher->decrypt(unpack("a8",pack("H16",substr($cyphertext,0,16))));
       $plaintext.=
           $cypher->decrypt(unpack("a8",pack("H16",substr($cyphertext,16,16))));
       $plaintext=substr($plaintext,1,ord(substr($plaintext,0,1)) );
       return $plaintext;
   }
   
 1;  1;
 __END__;  __END__;

Removed from v.1.1061  
changed lines
  Added in v.1.1183


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