Diff for /loncom/interface/loncommon.pm between versions 1.1115 and 1.1188

version 1.1115, 2013/02/19 17:30:35 version 1.1188, 2014/05/15 20:20:54
Line 69  use Apache::lontexconvert(); Line 69  use Apache::lontexconvert();
 use Apache::lonclonecourse();  use Apache::lonclonecourse();
 use Apache::lonuserutils();  use Apache::lonuserutils();
 use Apache::lonuserstate();  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 Text::Aspell;
 use Authen::Captcha;  use Authen::Captcha;
 use Captcha::reCAPTCHA;  use Captcha::reCAPTCHA;
   use Crypt::DES;
   use DynaLoader; # for Crypt::DES version
   
 # ---------------------------------------------- Designs  # ---------------------------------------------- Designs
 use vars qw(%defaultdesign);  use vars qw(%defaultdesign);
Line 531  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 594  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 752  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 847  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 993  sub select_language { Line 1006  sub select_language {
     my ($name,$selected,$includeempty) = @_;      my ($name,$selected,$includeempty) = @_;
     my %langchoices;      my %langchoices;
     if ($includeempty) {      if ($includeempty) {
         %langchoices = ('' => &mt('No language preference'));          %langchoices = ('' => 'No language preference');
     }      }
     foreach my $id (&languageids()) {      foreach my $id (&languageids()) {
         my $code = &supportedlanguagecode($id);          my $code = &supportedlanguagecode($id);
Line 1001  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);
 }  }
   
Line 1302  sub helpLatexCheatsheet { Line 1316  sub helpLatexCheatsheet {
   .&help_open_topic('Other_Symbols',&mt('Other Symbols'),$stayOnPage,undef,600)    .&help_open_topic('Other_Symbols',&mt('Other Symbols'),$stayOnPage,undef,600)
   .'</span>';    .'</span>';
     unless ($not_author) {      unless ($not_author) {
         $out .= ' <span>'          $out .= '<span>'
        .&help_open_topic('Authoring_Output_Tags',&mt('Output Tags'),$stayOnPage,undef,600)                 .&help_open_topic('Authoring_Output_Tags',&mt('Output Tags'),$stayOnPage,undef,600)
                  .'</span> <span>'
                  .&help_open_topic('Authoring_Multilingual_Problems',&mt('How to create problems in different languages'),$stayOnPage,undef,600)
        .'</span>';         .'</span>';
     }      }
     $out .= '</span>'; # End cheatsheet      $out .= '</span>'; # End cheatsheet
Line 1369  sub top_nav_help { Line 1385  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 1424  function helpMenu(target) { Line 1446  function helpMenu(target) {
     return;      return;
 }  }
 function writeHelp(caller) {  function writeHelp(caller) {
     caller.document.writeln('$start_page\\n<frame name="bannerframe" src="'+banner_link+'" />\\n<frame name="bodyframe" src="$details_link" />\\n$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 1738  RESIZE Line 1761  RESIZE
   
 =head1 Excel and CSV file utility routines  =head1 Excel and CSV file utility routines
   
 =over 4  
   
 =cut  =cut
   
 ###############################################################  ###############################################################
Line 1747  RESIZE Line 1768  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 2180  sub select_level_form { Line 2203  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 2193  If the $showdomdesc flag is set, the dom Line 2216  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 2332  Outputs: Line 2361  Outputs:
   
 =item * $clientos  =item * $clientos
   
   =item * $clientmobile
   
   =item * $clientinfo
   
 =back  =back
   
 =back   =back 
Line 2350  sub decode_user_agent { Line 2383  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 2361  sub decode_user_agent { Line 2395  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 2372  sub decode_user_agent { Line 2407  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 3043  sub get_related_words { Line 3086  sub get_related_words {
   
 =pod  =pod
   
   =back
   
 =head1 Spell checking  =head1 Spell checking
   
 =over 4  =over 4
Line 3076  Note: This sub assumes that aspell is in Line 3121  Note: This sub assumes that aspell is in
 =cut  =cut
   
   
 =pod  
   
 =back  
   
 =cut  
   
 sub check_spelling {  sub check_spelling {
     my ($wordlist, $language) = @_;      my ($wordlist, $language) = @_;
     my @misspellings;      my @misspellings;
Line 3297  sub screenname { Line 3336  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 3856  sub get_previous_attempt { Line 3895  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 3872  sub get_previous_attempt { Line 3911  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 3893  sub get_previous_attempt { Line 3932  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 3920  sub format_previous_attempt_value { Line 3961  sub format_previous_attempt_value {
             }               } 
         }          }
     } else {      } else {
  $value = &unescape($value);          $value = &HTML::Entities::encode(&unescape($value), '"<>&');
     }      }
     return $value;      return $value;
 }  }
Line 4915  sub designparm { Line 4956  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 4978  Input: (optional) filename from which br Line 5019  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 5009  sub CSTR_pageheader { Line 5050  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 5097  sub bodytag { Line 5138  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 5112  sub bodytag { Line 5154  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 5138  sub bodytag { Line 5183  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'},  
                                 undef,'LC_menubuttons_link');  
     }      }
           
     my $titleinfo = '<h1>'.$title.'</h1>';      my $titleinfo = '<h1>'.$title.'</h1>';
Line 5163  sub bodytag { Line 5206  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 5175  sub bodytag { Line 5213  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') {
Line 5262  sub make_attr_string { Line 5304  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 5393  form, .inline { Line 5435  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 6463  div.LC_edit_problem_saves { Line 6513  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 6477  div.LC_createcourse { Line 6540  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 6574  fieldset > legend { Line 6638  fieldset > legend {
 }  }
   
 ol.LC_primary_menu {  ol.LC_primary_menu {
   float: right;  
   margin: 0;    margin: 0;
   padding: 0;    padding: 0;
   background-color: $pgbg_or_bgcolor;    background-color: $pgbg_or_bgcolor;
Line 6718  ul#LC_secondary_menu li ul li { Line 6781  ul#LC_secondary_menu li ul li {
   vertical-align: top;    vertical-align: top;
   border-left: 1px solid black;    border-left: 1px solid black;
   border-right: 1px solid black;    border-right: 1px solid black;
   background-color: $data_table_light    background-color: $data_table_light;
   list-style:none;    list-style:none;
   float: none;    float: none;
 }  }
Line 7228  sub headtag { Line 7291  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 7238  sub headtag { Line 7302  sub headtag {
   
     my $result =      my $result =
  '<head>'.   '<head>'.
  &font_settings();   &font_settings($args);
   
     my $inhibitprint = &print_suppression();      my $inhibitprint;
       if ($args->{'print_suppress'}) {
           $inhibitprint = &print_suppression();
       }
   
     if (!$args->{'frameset'}) {      if (!$args->{'frameset'}) {
  $result .= &Apache::lonhtmlcommon::htmlareaheaders();   $result .= &Apache::lonhtmlcommon::htmlareaheaders();
Line 7251  sub headtag { Line 7318  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 7286  ADDMETA Line 7353  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          .$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 7298  ADDMETA Line 7374  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;
 }  }
Line 7398  Inputs: none Line 7480  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 7409  sub xml_begin { Line 7492  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 7478  sub start_page { Line 7564  sub start_page {
     my ($result,@advtools);      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 7579  function set_wishlistlink(title, path) { Line 7665  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 7622  var modalWindow = { Line 7710  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 7637  ENDMODAL Line 7725  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'; }
       unless ($transparency) { $transparency='true'; }
   
     my $target_attr;      my $target_attr;
     if (defined($target)) {      if (defined($target)) {
         $target_attr = 'target="'.$target.'"';          $target_attr = 'target="'.$target.'"';
     }      }
     return <<"ENDLINK";      return <<"ENDLINK";
 <a href="$link" $target_attr title="$title" onclick="javascript:openMyModal('$link',$width,$height,'$scrolling'); return false;">  <a href="$link" $target_attr title="$title" onclick="javascript:openMyModal('$link',$width,$height,'$scrolling','$transparency','$style'); return false;">
            $linktext</a>             $linktext</a>
 ENDLINK  ENDLINK
 }  }
Line 7673  sub modal_adhoc_inner { Line 7763  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 7796  sub LCprogressbar { Line 7886  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 7896  sub validate_page { Line 7984  sub validate_page {
   
   
 sub start_scrollbox {  sub start_scrollbox {
     my ($outerwidth,$width,$height,$id,$bgcolor)=@_;      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,$tdcol);      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 '') {      if ($bgcolor ne '') {
         $tdcol = "background-color: $bgcolor;";          $tdcol = "background-color: $bgcolor;";
     }      }
       my $nicescroll_js;
       if ($env{'browser.mobile'}) {
           $nicescroll_js = &nicescroll_javascript('div_'.$id,$cursor,$needjsready);
       }
     return <<"END";      return <<"END";
 <table style="width: $outerwidth; border: 1px solid none;"$table_id><tr><td style="width: $width;$tdcol"><div style="overflow:auto; width:$width; height: $height;"$div_id>  $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  END
 }  }
   
Line 7917  sub end_scrollbox { Line 8012  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).
  '<p class="LC_error">'.&mt($msg).'</p>'.   '<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 8214  sub get_sections { Line 8396  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 8241  sub get_sections { Line 8435  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 8388  sub get_course_users { Line 8585  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 8398  sub get_course_users { Line 8595  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 8433  sub get_course_users { Line 8634  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 8521  sub get_user_info { Line 8722  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 8539  Returns: Line 8745  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 8547  defined for the user's instituional stat Line 8753  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 8562  sub get_user_quota { Line 8768  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 8602  Retrieves default quota assigned for sto Line 8839  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 8663  sub default_quota { Line 8906  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 8681  sub default_quota { Line 8933  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 9122  sub personal_data_fieldtitles { Line 9432  sub personal_data_fieldtitles {
   
 sub sorted_inst_types {  sub sorted_inst_types {
     my ($dom) = @_;      my ($dom) = @_;
     my ($usertypes,$order) = &Apache::lonnet::retrieve_inst_usertypes($dom);      my ($usertypes,$order);
       my %domdefaults = &Apache::lonnet::get_domain_defaults($dom);
       if (ref($domdefaults{'inststatus'}) eq 'HASH') {
           $usertypes = $domdefaults{'inststatus'}{'inststatustypes'};
           $order = $domdefaults{'inststatus'}{'inststatusorder'};
       } else {
           ($usertypes,$order) = &Apache::lonnet::retrieve_inst_usertypes($dom);
       }
     my $othertitle = &mt('All users');      my $othertitle = &mt('All users');
     if ($env{'request.course.id'}) {      if ($env{'request.course.id'}) {
         $othertitle  = &mt('Any users');          $othertitle  = &mt('Any users');
Line 9520  sub ask_for_embedded_content { Line 9837  sub ask_for_embedded_content {
     my $numexisting = 0;      my $numexisting = 0;
     my $numunused = 0;      my $numunused = 0;
     my ($output,$upload_output,$toplevel,$url,$udom,$uname,$getpropath,$cdom,$cnum,      my ($output,$upload_output,$toplevel,$url,$udom,$uname,$getpropath,$cdom,$cnum,
         $fileloc,$filename,$delete_output,$modify_output,$title,$symb,$path);          $fileloc,$filename,$delete_output,$modify_output,$title,$symb,$path,$navmap);
     my $heading = &mt('Upload embedded files');      my $heading = &mt('Upload embedded files');
     my $buttontext = &mt('Upload');      my $buttontext = &mt('Upload');
   
     my $navmap;  
     if ($env{'request.course.id'}) {      if ($env{'request.course.id'}) {
         $navmap = Apache::lonnavmaps::navmap->new();          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')) {      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 9567  sub ask_for_embedded_content { Line 9888  sub ask_for_embedded_content {
         }          }
     } elsif ($actionurl eq '/adm/dependencies')  {      } elsif ($actionurl eq '/adm/dependencies')  {
         if ($env{'request.course.id'} ne '') {          if ($env{'request.course.id'} ne '') {
             $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};  
             $cnum =  $env{'course.'.$env{'request.course.id'}.'.num'};  
             if (ref($args) eq 'HASH') {              if (ref($args) eq 'HASH') {
                 $url = $args->{'docs_url'};                  $url = $args->{'docs_url'};
                 $title = $args->{'docs_title'};                  $title = $args->{'docs_title'};
                 $toplevel = "/$url";                  $toplevel = $url; 
                   unless ($toplevel =~ m{^/}) {
                       $toplevel = "/$url";
                   }
                 ($rem) = ($toplevel =~ m{^(.+/)[^/]+$});                  ($rem) = ($toplevel =~ m{^(.+/)[^/]+$});
                 ($path) =                    if ($toplevel =~ m{^(\Q/uploaded/$cdom/$cnum/portfolio/syllabus\E)}) {
                     ($toplevel =~ m{^(\Q/uploaded/$cdom/$cnum/\E(?:docs|supplemental)/(?:default|\d+)/\d+)/});                      $path = $1;
                   } else {
                       ($path) =
                           ($toplevel =~ m{^(\Q/uploaded/$cdom/$cnum/\E(?:docs|supplemental)/(?:default|\d+)/\d+)/});
                   }
                 $fileloc = &Apache::lonnet::filelocation('',$toplevel);                  $fileloc = &Apache::lonnet::filelocation('',$toplevel);
                 $fileloc =~ s{^/}{};                  $fileloc =~ s{^/}{};
                 ($filename) = ($fileloc =~ m{.+/([^/]+)$});                  ($filename) = ($fileloc =~ m{.+/([^/]+)$});
                 $heading = &mt('Status of dependencies in [_1]',"$title ($filename)");                  $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 9612  sub ask_for_embedded_content { Line 9952  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;
                 }                  }
             }              }
         }          }
Line 9622  sub ask_for_embedded_content { Line 9962  sub ask_for_embedded_content {
     my $dirptr = 16384;      my $dirptr = 16384;
     foreach my $path (keys(%subdependencies)) {      foreach my $path (keys(%subdependencies)) {
         $currsubfile{$path} = {};          $currsubfile{$path} = {};
         if (($actionurl eq '/adm/portfolio') || ($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') {
Line 9638  sub ask_for_embedded_content { Line 9979  sub ask_for_embedded_content {
             }              }
         } elsif (($actionurl eq '/adm/dependencies') ||          } elsif (($actionurl eq '/adm/dependencies') ||
                  (($actionurl eq '/adm/coursedocs') && (ref($args) eq 'HASH') &&                   (($actionurl eq '/adm/coursedocs') && (ref($args) eq 'HASH') &&
                   ($args->{'context'} eq 'paste'))) {                    ($args->{'context'} eq 'paste')) ||
                    ($actionurl eq "/public/$cdom/$cnum/syllabus")) {
             if ($env{'request.course.id'} ne '') {              if ($env{'request.course.id'} ne '') {
                 my ($dir) = ($fileloc =~ m{^(.+/)[^/]+$});                  my $dir;
                   if ($actionurl eq "/public/$cdom/$cnum/syllabus") {
                       $dir = $fileloc;
                   } else {
                       ($dir) = ($fileloc =~ m{^(.+/)[^/]+$});
                   }
                 if ($dir ne '') {                  if ($dir ne '') {
                     my ($sublistref,$listerror) =                      my ($sublistref,$listerror) =
                         &Apache::lonnet::dirlist($dir.$path,$cdom,$cnum,$getpropath,undef,'/');                          &Apache::lonnet::dirlist($dir.$path,$cdom,$cnum,$getpropath,undef,'/');
Line 9688  sub ask_for_embedded_content { Line 10035  sub ask_for_embedded_content {
         }          }
     }      }
     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 9704  sub ask_for_embedded_content { Line 10052  sub ask_for_embedded_content {
         }          }
     } elsif (($actionurl eq '/adm/dependencies') ||      } elsif (($actionurl eq '/adm/dependencies') ||
              (($actionurl eq '/adm/coursedocs') && (ref($args) eq 'HASH') &&               (($actionurl eq '/adm/coursedocs') && (ref($args) eq 'HASH') &&
               ($args->{'context'} eq 'paste'))) {                ($args->{'context'} eq 'paste')) ||
                ($actionurl eq "/public/$cdom/$cnum/syllabus")) {
         if ($env{'request.course.id'} ne '') {          if ($env{'request.course.id'} ne '') {
             my ($dir) = ($fileloc =~ m{^(.+/)[^/]+$});              my ($dir) = ($fileloc =~ m{^(.+/)[^/]+$});
             if ($dir ne '') {              if ($dir ne '') {
Line 9739  sub ask_for_embedded_content { Line 10088  sub ask_for_embedded_content {
                 ($file eq $filename.'.bak') ||                  ($file eq $filename.'.bak') ||
                 ($dependencies{$file})) {                  ($dependencies{$file})) {
             if ($actionurl eq '/adm/dependencies') {              if ($actionurl eq '/adm/dependencies') {
                 next if (($rem ne '') &&                  unless ($toplevel =~ m{^\Q/uploaded/$cdom/$cnum/portfolio/syllabus\E}) {
                          (($env{"httpref.$rem".$file} ne '') ||                      next if (($rem ne '') &&
                           (ref($navmap) &&                               (($env{"httpref.$rem".$file} ne '') ||
                           (($navmap->getResourceByUrl($rem.$file) ne '') ||                                (ref($navmap) &&
                            (($file =~ /^(.*\.s?html?)\.bak$/i) &&                                (($navmap->getResourceByUrl($rem.$file) ne '') ||
                             ($navmap->getResourceByUrl($rem.$1)))))));                                 (($file =~ /^(.*\.s?html?)\.bak$/i) &&
                                   ($navmap->getResourceByUrl($rem.$1)))))));
                   }
             }              }
             $unused{$file} = 1;              $unused{$file} = 1;
         }          }
Line 9753  sub ask_for_embedded_content { Line 10104  sub ask_for_embedded_content {
         ($args->{'context'} eq 'paste')) {          ($args->{'context'} eq 'paste')) {
         $counter = scalar(keys(%existing));          $counter = scalar(keys(%existing));
         $numpathchg = scalar(keys(%pathchanges));          $numpathchg = scalar(keys(%pathchanges));
         return ($output,$counter,$numpathchg,\%existing);           return ($output,$counter,$numpathchg,\%existing);
       } elsif (($actionurl eq "/public/$cdom/$cnum/syllabus") && 
                (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') {          if ($actionurl eq '/adm/dependencies') {
             next if ($embed_file =~ m{^\w+://});              next if ($embed_file =~ m{^\w+://});
         }          }
         $upload_output .= &start_data_table_row().          $upload_output .= &start_data_table_row().
                           '<td><img src="'.&icon($embed_file).'" />&nbsp;'.                            '<td valign="top"><img src="'.&icon($embed_file).'" />&nbsp;'.
                           '<span class="LC_filename">'.$embed_file.'</span>';                            '<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'} && $embed_file =~ m{^\w+://}) {           if ($args->{'ignore_remote_references'} && $embed_file =~ m{^\w+://}) { 
             $upload_output.='<span class="LC_warning">'.&mt("URL points to other server.").'</span>';              $upload_output.='<td align="right">'.
                               '<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.='<span class="LC_warning">'.&mt('Invalid characters').'</span>';              $upload_output.='<td align="right"><span class="LC_warning">'.
                               &mt('Invalid characters').'</span>';
             $numinvalid++;              $numinvalid++;
         } else {          } else {
             $upload_output .= &embedded_file_element('upload_embedded',$counter,              $upload_output .= '<td>'.
                                 &embedded_file_element('upload_embedded',$counter,
                                                      $embed_file,\%mapping,                                                       $embed_file,\%mapping,
                                                      $allfiles,$codebase,'upload');                                                       $allfiles,$codebase,'upload');
             $counter ++;              $counter ++;
Line 9803  sub ask_for_embedded_content { Line 10164  sub ask_for_embedded_content {
             $counter ++;              $counter ++;
         } else {          } else {
             $upload_output .= &start_data_table_row().              $upload_output .= &start_data_table_row().
                               '<td><span class="LC_filename">'.$embed_file.'</span></td>';                                '<td valign="top"><img src="'.&icon($embed_file).'" />&nbsp;'.
                               '<td><span class="LC_warning">'.&mt('Already exists').'</span></td>'.                                '<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";                                &Apache::loncommon::end_data_table_row()."\n";
         }          }
     }      }
Line 9899  sub ask_for_embedded_content { Line 10261  sub ask_for_embedded_content {
         $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 9942  sub ask_for_embedded_content { Line 10304  sub ask_for_embedded_content {
             $chgcount ++;              $chgcount ++;
         }          }
     }      }
     if ($counter) {      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 9955  sub ask_for_embedded_content { Line 10317  sub ask_for_embedded_content {
         } elsif ($actionurl eq '/adm/dependencies') {          } elsif ($actionurl eq '/adm/dependencies') {
             $output .= '<input type="hidden" name="action" value="process_changes" />';              $output .= '<input type="hidden" name="action" value="process_changes" />';
         }          }
         $output .=  '<input type ="submit" value="'.$buttontext.'" />'."\n".'</form>'."\n";          $output .= '<input type ="submit" value="'.$buttontext.'" />'."\n".'</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);      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];
       }
   }
   
 sub embedded_file_element {  sub embedded_file_element {
     my ($context,$num,$embed_file,$mapping,$allfiles,$codebase,$type) = @_;      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') &&
Line 10090  sub upload_embedded { Line 10492  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 10123  sub upload_embedded { Line 10528  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 10136  sub upload_embedded { Line 10542  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 10267  sub modify_html_form { Line 10676  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'};
Line 10276  sub modify_html_refs { Line 10685  sub modify_html_refs {
     } elsif ($context eq 'manage_dependencies') {      } elsif ($context eq 'manage_dependencies') {
         (undef,undef,$container) = &Apache::lonnet::decode_symb($env{'form.symb'});          (undef,undef,$container) = &Apache::lonnet::decode_symb($env{'form.symb'});
         $container = "/$container";          $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');
     unless (@changes > 0) {      unless ((@changes > 0) || ($context eq 'syllabus')) {
         if (wantarray) {          if (wantarray) {
             return ('',0,0);               return ('',0,0); 
         } else {          } else {
Line 10289  sub modify_html_refs { Line 10700  sub modify_html_refs {
         }          }
     }      }
     if (($context eq 'portfolio') || ($context eq 'coursedoc') ||       if (($context eq 'portfolio') || ($context eq 'coursedoc') || 
         ($context eq 'manage_dependencies')) {          ($context eq 'manage_dependencies') || ($context eq 'syllabus')) {
         unless ($container =~ m{^/uploaded/\Q$udom\E/\Q$uname\E/}) {          unless ($container =~ m{^/uploaded/\Q$udom\E/\Q$uname\E/}) {
             if (wantarray) {              if (wantarray) {
                 return ('',0,0);                  return ('',0,0);
Line 10345  sub modify_html_refs { Line 10756  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 10353  sub modify_html_refs { Line 10766  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 '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{/([^/]+)$});
Line 10369  sub modify_html_refs { Line 10783  sub modify_html_refs {
                                    '<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 10384  sub modify_html_refs { Line 10803  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);
Line 10473  sub check_for_upload { Line 10933  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 10486  sub check_for_upload { Line 10946  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);                    '<p>'.&mt('Disk quota is [_1] kilobytes. Your current disk usage is [_2] kilobytes.',$disk_quota,$current_disk_usage).'</p>';
         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 10591  sub decompress_form { Line 11051  sub decompress_form {
         }          }
     }      }
     if ($mimetype =~ m{^application/(x\-)?(compressed|zip)}) {      if ($mimetype =~ m{^application/(x\-)?(compressed|zip)}) {
         my @camtasia = ("$topdir/","$topdir/index.html",          my @camtasia6 = ("$topdir/","$topdir/index.html",
                         "$topdir/media/",                          "$topdir/media/",
                         "$topdir/media/$topdir.mp4",                          "$topdir/media/$topdir.mp4",
                         "$topdir/media/FirstFrame.png",                          "$topdir/media/FirstFrame.png",
                         "$topdir/media/player.swf",                          "$topdir/media/player.swf",
                         "$topdir/media/swfobject.js",                          "$topdir/media/swfobject.js",
                         "$topdir/media/expressInstall.swf");                          "$topdir/media/expressInstall.swf");
         my @diffs = &compare_arrays(\@paths,\@camtasia);          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) {          if (@diffs == 0) {
             $is_camtasia = 1;              $is_camtasia = 6;
           } else {
               @diffs = &compare_arrays(\@paths,\@camtasia8);
               if (@diffs == 0) {
                   $is_camtasia = 8;
               }
         }          }
     }      }
     my $output;      my $output;
Line 10612  sub decompress_form { Line 11099  sub decompress_form {
 function camtasiaToggle() {  function camtasiaToggle() {
     for (var i=0; i<document.uploaded_decompress.autoextract_camtasia.length; i++) {      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].checked) {
             if (document.uploaded_decompress.autoextract_camtasia[i].value == 1) {              if (document.uploaded_decompress.autoextract_camtasia[i].value == $is_camtasia) {
   
                 document.getElementById('camtasia_titles').style.display='block';                  document.getElementById('camtasia_titles').style.display='block';
             } else {              } else {
Line 10675  ENDCAM Line 11162  ENDCAM
     if ($is_camtasia) {      if ($is_camtasia) {
         $output .= $lt{'auto'}.'<br />'.          $output .= $lt{'auto'}.'<br />'.
                    '<span class="LC_nobreak">'.$lt{'proa'}.'<label>'.                     '<span class="LC_nobreak">'.$lt{'proa'}.'<label>'.
                    '<input type="radio" name="autoextract_camtasia" value="1" onclick="javascript:camtasiaToggle();" checked="checked" />'.                     '<input type="radio" name="autoextract_camtasia" value="'.$is_camtasia.'" onclick="javascript:camtasiaToggle();" checked="checked" />'.
                    $lt{'yes'}.'</label>&nbsp;<label>'.                     $lt{'yes'}.'</label>&nbsp;<label>'.
                    '<input type="radio" name="autoextract_camtasia" value="0" onclick="javascript:camtasiaToggle();" />'.                     '<input type="radio" name="autoextract_camtasia" value="0" onclick="javascript:camtasiaToggle();" />'.
                    $lt{'no'}.'</label></span><br />'.                     $lt{'no'}.'</label></span><br />'.
Line 10798  sub decompress_uploaded_file { Line 11285  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 10908  sub process_decompression { Line 11395  sub process_decompression {
                                                            \%titles,\%children);                                                             \%titles,\%children);
                         }                          }
                         if ($env{'form.autoextract_camtasia'}) {                          if ($env{'form.autoextract_camtasia'}) {
                               my $version = $env{'form.autoextract_camtasia'};
                             my %displayed;                              my %displayed;
                             my $total = 1;                              my $total = 1;
                             $env{'form.archive_directory'} = [];                              $env{'form.archive_directory'} = [];
Line 10926  sub process_decompression { Line 11414  sub process_decompression {
                                     $env{'form.archive_'.$i} = 'display';                                      $env{'form.archive_'.$i} = 'display';
                                     $env{'form.archive_title_'.$i} = $env{'form.camtasia_foldername'};                                      $env{'form.archive_title_'.$i} = $env{'form.camtasia_foldername'};
                                     $displayed{'folder'} = $i;                                      $displayed{'folder'} = $i;
                                 } elsif ($item eq "$contents[0]/index.html") {                                  } 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_'.$i} = 'display';
                                     $env{'form.archive_title_'.$i} = $env{'form.camtasia_moviename'};                                      $env{'form.archive_title_'.$i} = $env{'form.camtasia_moviename'};
                                     $displayed{'web'} = $i;                                      $displayed{'web'} = $i;
                                 } else {                                  } else {
                                     if ($item eq "$contents[0]/media") {                                      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);                                          push(@{$env{'form.archive_directory'}},$i);
                                     }                                      }
                                     $env{'form.archive_'.$i} = 'dependency';                                      $env{'form.archive_'.$i} = 'dependency';
Line 11658  sub cleanup_empty_dirs { Line 12149  sub cleanup_empty_dirs {
   
 =pod  =pod
   
 =item &get_folder_hierarchy()  =item * &get_folder_hierarchy()
   
 Provides hierarchy of names of folders/sub-folders containing the current  Provides hierarchy of names of folders/sub-folders containing the current
 item,  item,
Line 11686  sub get_folder_hierarchy { Line 12177  sub get_folder_hierarchy {
                 my @pcs = split(/,/,$pcslist);                  my @pcs = split(/,/,$pcslist);
                 foreach my $pc (@pcs) {                  foreach my $pc (@pcs) {
                     if ($pc == 1) {                      if ($pc == 1) {
                         push(@pathitems,&mt('Main Course Documents'));                          push(@pathitems,&mt('Main Content'));
                     } else {                      } else {
                         my $res = $navmap->getByMapPc($pc);                          my $res = $navmap->getByMapPc($pc);
                         if (ref($res)) {                          if (ref($res)) {
Line 11701  sub get_folder_hierarchy { Line 12192  sub get_folder_hierarchy {
             }              }
             if ($showitem) {              if ($showitem) {
                 if ($mapres->{ID} eq '0.0') {                  if ($mapres->{ID} eq '0.0') {
                     push(@pathitems,&mt('Main Course Documents'));                      push(@pathitems,&mt('Main Content'));
                 } else {                  } else {
                     my $maptitle = $mapres->compTitle();                      my $maptitle = $mapres->compTitle();
                     $maptitle =~ s/\W+/_/g;                      $maptitle =~ s/\W+/_/g;
Line 11768  sub get_turnedin_filepath { Line 12259  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 11776  sub get_turnedin_filepath { Line 12270  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 11816  sub get_turnedin_filepath { Line 12313  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 12753  sub restore_settings { Line 13253  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 12958  sub extract_categories { Line 13462  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 13029  sub recurse_categories { Line 13533  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 13106  sub assign_categories_table { Line 13610  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 13140  sub assign_category_rows { Line 13644  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 13172  sub assign_category_rows { Line 13676  sub assign_category_rows {
     return $text;      return $text;
 }  }
   
   =pod
   
   =back
   
   =cut
   
 ############################################################  ############################################################
 ############################################################  ############################################################
   
Line 13188  sub commit_customrole { Line 13698  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 13197  sub commit_standardrole { Line 13707  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 13228  sub commit_standardrole { Line 13738  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 13275  sub commit_studentrole { Line 13786  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 13419  sub check_clone { Line 13934  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 13515  sub construct_course { Line 14030  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 13544  sub construct_course { Line 14064  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 13568  sub construct_course { Line 14091  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 13692  sub construct_course { Line 14220  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 13760  sub construct_course { Line 14307  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 13787  sub group_term { Line 14388  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 13924  sub init_user_environment { Line 14526  sub init_user_environment {
 # ------------------------------------ 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 13955  sub init_user_environment { Line 14557  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 13974  sub init_user_environment { Line 14578  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') {
Line 13986  sub init_user_environment { Line 14596  sub init_user_environment {
                                                   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',
Line 14091  sub clean_symb { Line 14701  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 [_1]',$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 14207  sub parse_supplemental_title { Line 15346  sub parse_supplemental_title {
     return $title;      return $title;
 }  }
   
   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 {  sub symb_to_docspath {
     my ($symb) = @_;      my ($symb) = @_;
     return unless ($symb);      return unless ($symb);
Line 14236  sub symb_to_docspath { Line 15399  sub symb_to_docspath {
                     my $thistitle = $res->title();                      my $thistitle = $res->title();
                     $path .= '&'.                      $path .= '&'.
                              &Apache::lonhtmlcommon::entity_encode($thisurl).'&'.                               &Apache::lonhtmlcommon::entity_encode($thisurl).'&'.
                              &Apache::lonhtmlcommon::entity_encode($thistitle).                               &escape($thistitle).
                              ':'.$res->randompick().                               ':'.$res->randompick().
                              ':'.$res->randomout().                               ':'.$res->randomout().
                              ':'.$res->encrypted().                               ':'.$res->encrypted().
Line 14248  sub symb_to_docspath { Line 15411  sub symb_to_docspath {
         $path =~ s/^\&//;          $path =~ s/^\&//;
         my $maptitle = $mapresobj->title();          my $maptitle = $mapresobj->title();
         if ($mapurl eq 'default') {          if ($mapurl eq 'default') {
             $maptitle = 'Main Course Documents';              $maptitle = 'Main Content';
         }          }
         $path .= (($path ne '')? '&' : '').          $path .= (($path ne '')? '&' : '').
                  &Apache::lonhtmlcommon::entity_encode($mapurl).'&'.                   &Apache::lonhtmlcommon::entity_encode($mapurl).'&'.
                  &Apache::lonhtmlcommon::entity_encode($maptitle).                   &escape($maptitle).
                  ':'.$mapresobj->randompick().                   ':'.$mapresobj->randompick().
                  ':'.$mapresobj->randomout().                   ':'.$mapresobj->randomout().
                  ':'.$mapresobj->encrypted().                   ':'.$mapresobj->encrypted().
Line 14262  sub symb_to_docspath { Line 15425  sub symb_to_docspath {
         my $maptitle = &Apache::lonnet::gettitle($mapurl);          my $maptitle = &Apache::lonnet::gettitle($mapurl);
         my $ispage = (($type eq 'page')? 1 : '');          my $ispage = (($type eq 'page')? 1 : '');
         if ($mapurl eq 'default') {          if ($mapurl eq 'default') {
             $maptitle = 'Main Course Documents';              $maptitle = 'Main Content';
         }          }
         $path = &Apache::lonhtmlcommon::entity_encode($mapurl).'&'.          $path = &Apache::lonhtmlcommon::entity_encode($mapurl).'&'.
                 &Apache::lonhtmlcommon::entity_encode($maptitle).':::::'.$ispage;                  &escape($maptitle).':::::'.$ispage;
     }      }
     unless ($mapurl eq 'default') {      unless ($mapurl eq 'default') {
         $path = 'default&'.          $path = 'default&'.
                 &Apache::lonhtmlcommon::entity_encode('Main Course Documents').                  &escape('Main Content').
                 ':::::&'.$path;                  ':::::&'.$path;
     }      }
     return $path;      return $path;
Line 14282  sub captcha_display { Line 15445  sub captcha_display {
     if ($captcha eq 'original') {      if ($captcha eq 'original') {
         $output = &create_captcha();          $output = &create_captcha();
         unless ($output) {          unless ($output) {
             $error = 'captcha';               $error = 'captcha';
         }          }
     } elsif ($captcha eq 'recaptcha') {      } elsif ($captcha eq 'recaptcha') {
         $output = &create_recaptcha($pubkey);          $output = &create_recaptcha($pubkey);
         unless ($output) {          unless ($output) {
             $error = 'recaptcha';               $error = 'recaptcha';
         }          }
     }      }
     return ($output,$error);      return ($output,$error,$captcha);
 }  }
   
 sub captcha_response {  sub captcha_response {
Line 14366  sub create_captcha { Line 15529  sub create_captcha {
         if (-e $Apache::lonnet::perlvar{'lonCaptchaDir'}.'/'.$md5sum.'.png') {          if (-e $Apache::lonnet::perlvar{'lonCaptchaDir'}.'/'.$md5sum.'.png') {
             $output = '<input type="hidden" name="crypt" value="'.$md5sum.'" />'."\n".              $output = '<input type="hidden" name="crypt" value="'.$md5sum.'" />'."\n".
                       &mt('Type in the letters/numbers shown below').'&nbsp;'.                        &mt('Type in the letters/numbers shown below').'&nbsp;'.
                      '<input type="text" size="5" name="code" value="" /><br />'.                        '<input type="text" size="5" name="code" value="" autocomplete="off" />'.
                      '<img src="'.$captcha_params{'www_output_dir'}.'/'.$md5sum.'.png" />';                        '<br />'.
                         '<img src="'.$captcha_params{'www_output_dir'}.'/'.$md5sum.'.png" alt="captcha" />';
             last;              last;
         }          }
     }      }
Line 14408  sub check_captcha { Line 15572  sub check_captcha {
   
 sub create_recaptcha {  sub create_recaptcha {
     my ($pubkey) = @_;      my ($pubkey) = @_;
       my $use_ssl;
       if ($ENV{'SERVER_PORT'} == 443) {
           $use_ssl = 1;
       }
     my $captcha = Captcha::reCAPTCHA->new;      my $captcha = Captcha::reCAPTCHA->new;
     return $captcha->get_options_setter({theme => 'white'})."\n".      return $captcha->get_options_setter({theme => 'white'})."\n".
            $captcha->get_html($pubkey).             $captcha->get_html($pubkey,undef,$use_ssl).
            &mt('If either word is hard to read, [_1] will replace them.',             &mt('If either word is hard to read, [_1] will replace them.',
                '<image src="/res/adm/pages/refresh.gif" alt="reCAPTCHA refresh" />').                 '<img src="/res/adm/pages/refresh.gif" alt="reCAPTCHA refresh" />').
            '<br /><br />';             '<br /><br />';
 }  }
   
Line 14433  sub check_recaptcha { Line 15601  sub check_recaptcha {
     return $captcha_chk;      return $captcha_chk;
 }  }
   
 =pod  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);
   }
   
 =back  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;
   }
   
 =cut  # 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.1115  
changed lines
  Added in v.1.1188


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